<!DOCTYPE html>
<html dir="ltr" lang="zh">
<head>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<meta content="创建型模式 # 创建型模式的主要关注点是“怎样创建对象？”，它的主要特点是“将对象的创建与使用分离”。
这样可以降低系统的耦合度，并且使用者不需要关注对象的创建细节。
1 单例设计模式 # 1.1 概述 # 单例模式（Singleton Pattern）是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式，它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类，该类负责创建自己的对象，同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式，可以直接访问，不需要实例化该类的对象。
1.2 结构 # 单例模式的主要有以下角色：
单例类。只能创建一个实例的类 访问类。使用单例类 1.3 案例实现 # 单例设计模式分类两种：
​	饿汉式：类加载就会导致该单实例对象被创建
​	懒汉式：类加载不会导致该单实例对象被创建，而是首次使用该对象时才会创建
1.2.1 饿汉式 # 方式1（静态变量方式）
点击展开 ... /** * 饿汉式 * 静态变量创建类的对象 */ public class Singleton { //私有构造方法 private Singleton() {} //在成员位置创建该类的对象 private static Singleton instance = new Singleton(); //对外提供静态方法获取该对象 public static Singleton getInstance() { return instance; } } 说明：
​	该方式在成员位置声明Singleton类型的静态变量，并创建Singleton类的对象instance。instance对象是随着类的加载而创建的。如果该对象足够大的话，而一直没有使用就会造成内存的浪费。" name="description"/>
<meta content="#FFFFFF" name="theme-color"/>
<meta content="light dark" name="color-scheme"/><meta content="" property="og:title"/>
<meta content="创建型模式 # 创建型模式的主要关注点是“怎样创建对象？”，它的主要特点是“将对象的创建与使用分离”。
这样可以降低系统的耦合度，并且使用者不需要关注对象的创建细节。
1 单例设计模式 # 1.1 概述 # 单例模式（Singleton Pattern）是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式，它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类，该类负责创建自己的对象，同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式，可以直接访问，不需要实例化该类的对象。
1.2 结构 # 单例模式的主要有以下角色：
单例类。只能创建一个实例的类 访问类。使用单例类 1.3 案例实现 # 单例设计模式分类两种：
​	饿汉式：类加载就会导致该单实例对象被创建
​	懒汉式：类加载不会导致该单实例对象被创建，而是首次使用该对象时才会创建
1.2.1 饿汉式 # 方式1（静态变量方式）
点击展开 ... /** * 饿汉式 * 静态变量创建类的对象 */ public class Singleton { //私有构造方法 private Singleton() {} //在成员位置创建该类的对象 private static Singleton instance = new Singleton(); //对外提供静态方法获取该对象 public static Singleton getInstance() { return instance; } } 说明：
​	该方式在成员位置声明Singleton类型的静态变量，并创建Singleton类的对象instance。instance对象是随着类的加载而创建的。如果该对象足够大的话，而一直没有使用就会造成内存的浪费。" property="og:description"/>
<meta content="article" property="og:type"/>
<meta content="https://helloputong.gitee.io/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E5%88%9B%E5%BB%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F/" property="og:url"/><meta content="notes" property="article:section"/>
<title>创建型模式 | Hello! 噗通 🍀</title>
<link href="/manifest.json" rel="manifest"/>
<link href="/favicon.png" rel="icon" type="image/x-icon"/>
<link crossorigin="anonymous" href="/book.min.a82d7e77ceb134d151c4d7e381eeb30623fbd5a524d58c584d8716ecec0205bd.css" integrity="sha256-qC1+d86xNNFRxNfjge6zBiP71aUk1YxYTYcW7OwCBb0=" rel="stylesheet"/>
<script defer="" src="/flexsearch.min.js"></script>
<script crossorigin="anonymous" defer="" integrity="sha256-+pR/j4Voa/VXQmH38FekcfPx1IEWD5WAkNOJruKNmQk=" src="/zh.search.min.fa947f8f85686bf5574261f7f057a471f3f1d481160f958090d389aee28d9909.js"></script>
<script crossorigin="anonymous" defer="" integrity="sha256-b2+Q/LjrHEnsOJg45rgB0N4ZQwuOUWkC+NdcPIvZhzk=" src="/sw.min.6f6f90fcb8eb1c49ec389838e6b801d0de19430b8e516902f8d75c3c8bd98739.js"></script>
<!--
Made with Book Theme
https://github.com/alex-shpak/hugo-book
-->
</head>
<body dir="ltr">
<input class="hidden toggle" id="menu-control" type="checkbox"/>
<input class="hidden toggle" id="toc-control" type="checkbox"/>
<main class="container flex">
<aside class="book-menu">
<div class="book-menu-content">
<nav>
<h2 class="book-brand">
<a class="flex align-center" href="/"><span>Hello! 噗通 🍀</span>
</a>
</h2>
<div class="book-search">
<input aria-label="Search" data-hotkeys="s/" id="book-search-input" maxlength="64" placeholder="Search" type="text"/>
<div class="book-search-spinner hidden"></div>
<ul id="book-search-results"></ul>
</div>
<ul>
<li class="book-section-flat">
<span>--学习笔记--👇</span>
<ul>
<li>
<input class="toggle" id="section-62161c8b7eae8ea89aee3d6f310b2312" type="checkbox"/>
<label class="flex justify-between" for="section-62161c8b7eae8ea89aee3d6f310b2312">
<a class="" role="button">Android</a>
</label>
<ul>
<li>
<a class="" href="/notes/android/mac%E9%80%9A%E8%BF%87homebrew%E5%AE%89%E8%A3%85java8/">Mac 通过 Homebrew 安装 Java8</a>
</li>
<li>
<a class="" href="/notes/android/%E6%B4%BB%E5%8A%A8%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F/">活动的生命周期</a>
</li>
<li>
<a class="" href="/notes/android/%E5%B8%B8%E7%94%A8%E6%8E%A7%E4%BB%B6%E5%92%8C4%E7%A7%8D%E5%B8%83%E5%B1%80/">常用控件和4种布局</a>
</li>
<li>
<a class="" href="/notes/android/android-%E4%B8%AD%E4%BA%8B%E4%BB%B6%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/">Android 中事件学习总结</a>
</li>
<li>
<a class="" href="/notes/android/android-%E4%B8%AD%E7%9A%84%E6%B6%88%E6%81%AF%E6%9C%BA%E5%88%B6%E5%92%8C%E5%BC%82%E6%AD%A5%E4%BB%BB%E5%8A%A1/">Android 中的消息机制和异步任务</a>
</li>
<li>
<a class="" href="/notes/android/listview%E4%B8%AD%E5%85%B3%E4%BA%8E%E6%95%B0%E6%8D%AE%E6%9B%B4%E6%96%B0%E7%9A%84%E4%B8%A4%E4%B8%AA%E9%97%AE%E9%A2%98/">List View中关于数据更新的两个问题</a>
</li>
<li>
<a class="" href="/notes/android/spinner-%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8/">Spinner 基本使用</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-d1dc8d9746f5c776e8a82499bbb2e7c6" type="checkbox"/>
<label class="flex justify-between" for="section-d1dc8d9746f5c776e8a82499bbb2e7c6">
<a class="" role="button">BMS</a>
</label>
<ul>
<li>
<a class="" href="/notes/bms/bms-%E7%9B%B8%E5%85%B3%E7%90%86%E8%AE%BA%E5%AD%A6%E4%B9%A0/">BMS 相关概念</a>
</li>
<li>
<a class="" href="/notes/bms/%E6%BC%94%E7%A4%BA%E5%8F%82%E6%95%B0%E8%A7%A3%E8%AF%BB/">功能演示</a>
</li>
<li>
<a class="" href="/notes/bms/%E5%8E%9F%E7%90%86%E5%9B%BE%E8%A7%A3%E8%AF%BB/">原理图解读</a>
</li>
<li>
<a class="" href="/notes/bms/%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/">源码解析</a>
</li>
</ul>
</li>
<li>
<input checked="" class="toggle" id="section-b7444509cb631180897a34f028407c2c" type="checkbox"/>
<label class="flex justify-between" for="section-b7444509cb631180897a34f028407c2c">
<a class="" role="button">设计模式</a>
</label>
<ul>
<li>
<a class="" href="/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/uml-%E5%9B%BE/">Uml 图</a>
</li>
<li>
<a class="" href="/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%88%99/">设计原则</a>
</li>
<li>
<a class="active" href="/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E5%88%9B%E5%BB%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F/">创建型模式</a>
</li>
<li>
<a class="" href="/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E7%BB%93%E6%9E%84%E5%9E%8B%E6%A8%A1%E5%BC%8F/">结构型模式</a>
</li>
<li>
<a class="" href="/notes/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%A1%8C%E4%B8%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F/">行为型模式</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-4364152b7ab5995d509c0b7b811005c4" type="checkbox"/>
<label class="flex justify-between" for="section-4364152b7ab5995d509c0b7b811005c4">
<a class="" role="button">JVM</a>
</label>
<ul>
<li>
<a class="" href="/notes/jvm/%E4%BB%80%E4%B9%88%E6%98%AF-jvm/">什么是 Jvm</a>
</li>
<li>
<a class="" href="/notes/jvm/%E7%A8%8B%E5%BA%8F%E8%AE%A1%E6%95%B0%E5%99%A8/">程序计数器</a>
</li>
<li>
<a class="" href="/notes/jvm/%E8%99%9A%E6%8B%9F%E6%9C%BA%E6%A0%88/">虚拟机栈</a>
</li>
<li>
<a class="" href="/notes/jvm/%E6%9C%AC%E5%9C%B0%E6%96%B9%E6%B3%95%E6%A0%88-/">本地方法栈</a>
</li>
<li>
<a class="" href="/notes/jvm/%E5%A0%86/">堆</a>
</li>
<li>
<a class="" href="/notes/jvm/%E6%96%B9%E6%B3%95%E5%8C%BA/">方法区</a>
</li>
<li>
<a class="" href="/notes/jvm/%E7%9B%B4%E6%8E%A5%E5%86%85%E5%AD%98/">直接内存</a>
</li>
<li>
<a class="" href="/notes/jvm/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6/">垃圾回收</a>
</li>
<li>
<a class="" href="/notes/jvm/%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E5%99%A8/">垃圾回收器</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-61661238f18c0095524962a5d1d6e676" type="checkbox"/>
<label class="flex justify-between" for="section-61661238f18c0095524962a5d1d6e676">
<a class="" role="button">Spring</a>
</label>
<ul>
<li>
<a class="" href="/notes/spring/beanfactory%E4%B8%8Eapplicationcontext/">Bean Factory与 Application Context</a>
</li>
<li>
<a class="" href="/notes/spring/nacos-%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83/">Nacos 配置中心</a>
</li>
<li>
<a class="" href="/notes/spring/open-feign-%E8%BF%9C%E7%A8%8B%E8%B0%83%E7%94%A8%E7%A4%BA%E4%BE%8B/">Open Feign 远程调用示例</a>
</li>
<li>
<a class="" href="/notes/spring/springboot-%E6%95%B4%E5%90%88-mybatis-plus/">Spring Boot 整合 My Batis Plus</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-39abd0d44427d4a54e694a2b3f22d967" type="checkbox"/>
<label class="flex justify-between" for="section-39abd0d44427d4a54e694a2b3f22d967">
<a class="" role="button">TensorFlow</a>
</label>
<ul>
<li>
<a class="" href="/notes/tensorflow/tensorflow-%E7%AC%94%E8%AE%B0%E4%B8%80/">Tensor Flow 笔记（一）</a>
</li>
<li>
<a class="" href="/notes/tensorflow/tensorflow-%E7%AC%94%E8%AE%B0%E4%BA%8C/">Tensor Flow 笔记（二）</a>
</li>
<li>
<a class="" href="/notes/tensorflow/tensorflow-%E7%AC%94%E8%AE%B0%E4%B8%89/">Tensor Flow 笔记（三）</a>
</li>
<li>
<a class="" href="/notes/tensorflow/tensorflow-%E7%AC%94%E8%AE%B0%E5%9B%9B/">Tensor Flow 笔记（四）</a>
</li>
<li>
<a class="" href="/notes/tensorflow/tensorflow-%E7%AC%94%E8%AE%B0%E4%BA%94/">Tensor Flow 笔记（五）</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-e2ca0d138d67d9d3ae55da25ac044829" type="checkbox"/>
<label class="flex justify-between" for="section-e2ca0d138d67d9d3ae55da25ac044829">
<a class="" role="button">Redis</a>
</label>
<ul>
<li>
<a class="" href="/notes/redis/nosql%E6%95%B0%E6%8D%AE%E5%BA%93%E7%AE%80%E4%BB%8B/">No Sql数据库简介</a>
</li>
<li>
<a class="" href="/notes/redis/redis-key/">Redis Key</a>
</li>
<li>
<a class="" href="/notes/redis/redis-string/">Redis String</a>
</li>
<li>
<a class="" href="/notes/redis/redis-list/">Redis List</a>
</li>
<li>
<a class="" href="/notes/redis/redis-set/">Redis Set</a>
</li>
<li>
<a class="" href="/notes/redis/redis-hash/">Redis Hash</a>
</li>
<li>
<a class="" href="/notes/redis/redis-zset/">Redis Zset</a>
</li>
<li>
<a class="" href="/notes/redis/redis-%E5%8F%91%E5%B8%83%E4%B8%8E%E8%AE%A2%E9%98%85/">Redis 发布与订阅</a>
</li>
<li>
<a class="" href="/notes/redis/redis-jedis/">Redis Jedis</a>
</li>
<li>
<a class="" href="/notes/redis/springboot-%E6%95%B4%E5%90%88-redis/">Spring Boot 整合 Redis</a>
</li>
<li>
<a class="" href="/notes/redis/redis-%E4%BA%8B%E5%8A%A1%E5%92%8C%E9%94%81%E6%9C%BA%E5%88%B6/">Redis 事务和锁机制</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-58f730a0b22fcdc7a886db614d77f88c" type="checkbox"/>
<label class="flex justify-between" for="section-58f730a0b22fcdc7a886db614d77f88c">
<a class="" role="button">代码随想录刷题</a>
</label>
<ul>
<li>
<a class="" href="/notes/leetcode/day001-%E7%AC%AC%E4%B8%80%E7%AB%A0%E6%95%B0%E7%BB%84/">Day001 第一章数组</a>
</li>
<li>
<a class="" href="/notes/leetcode/day002-%E7%AC%AC%E4%B8%80%E7%AB%A0%E6%95%B0%E7%BB%84/">Day002 第一章数组</a>
</li>
<li>
<a class="" href="/notes/leetcode/day003-%E7%AC%AC%E4%BA%8C%E7%AB%A0%E9%93%BE%E8%A1%A8/">Day003 第二章链表</a>
</li>
<li>
<a class="" href="/notes/leetcode/day004-%E7%AC%AC%E4%BA%8C%E7%AB%A0%E9%93%BE%E8%A1%A8/">Day004 第二章链表</a>
</li>
<li>
<a class="" href="/notes/leetcode/day006-%E7%AC%AC%E4%B8%89%E7%AB%A0%E5%93%88%E5%B8%8C%E8%A1%A8/">Day006 第三章哈希表</a>
</li>
<li>
<a class="" href="/notes/leetcode/day007-%E7%AC%AC%E4%B8%89%E7%AB%A0%E5%93%88%E5%B8%8C%E8%A1%A8/">Day007 第三章哈希表</a>
</li>
<li>
<a class="" href="/notes/leetcode/day008-%E7%AC%AC%E5%9B%9B%E7%AB%A0%E5%AD%97%E7%AC%A6%E4%B8%B2/">Day008 第四章字符串</a>
</li>
<li>
<a class="" href="/notes/leetcode/day009-%E7%AC%AC%E5%9B%9B%E7%AB%A0%E5%AD%97%E7%AC%A6%E4%B8%B2/">Day009 第四章字符串</a>
</li>
<li>
<a class="" href="/notes/leetcode/day010-%E7%AC%AC%E4%BA%94%E7%AB%A0%E6%A0%88%E4%B8%8E%E9%98%9F%E5%88%97/">Day010 第五章栈与队列</a>
</li>
<li>
<a class="" href="/notes/leetcode/day011-%E7%AC%AC%E4%BA%94%E7%AB%A0%E6%A0%88%E4%B8%8E%E9%98%9F%E5%88%97/">Day011 第五章栈与队列</a>
</li>
<li>
<a class="" href="/notes/leetcode/day013-%E7%AC%AC%E4%BA%94%E7%AB%A0%E6%A0%88%E4%B8%8E%E9%98%9F%E5%88%97/">Day013 第五章栈与队列</a>
</li>
<li>
<a class="" href="/notes/leetcode/day014-%E7%AC%AC%E5%85%AD%E7%AB%A0%E4%BA%8C%E5%8F%89%E6%A0%91/">Day014 第六章二叉树</a>
</li>
<li>
<a class="" href="/notes/leetcode/day015-%E7%AC%AC%E5%85%AD%E7%AB%A0%E4%BA%8C%E5%8F%89%E6%A0%91/">Day015 第六章二叉树</a>
</li>
<li>
<a class="" href="/notes/leetcode/day017-%E7%AC%AC%E5%85%AD%E7%AB%A0%E4%BA%8C%E5%8F%89%E6%A0%91/">Day017 第六章二叉树</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-4f95435d3a74007e2c985ea455bbb6e6" type="checkbox"/>
<label class="flex justify-between" for="section-4f95435d3a74007e2c985ea455bbb6e6">
<a class="" role="button">MyBatisPlus</a>
</label>
<ul>
<li>
<a class="" href="/notes/mybatisplus/%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/">MP快速入门</a>
</li>
<li>
<a class="" href="/notes/mybatisplus/%E4%B8%80%E8%88%AC%E6%9F%A5%E8%AF%A2%E6%93%8D%E4%BD%9C/">一般查询操作</a>
</li>
<li>
<a class="" href="/notes/mybatisplus/%E5%88%86%E9%A1%B5%E6%9F%A5%E8%AF%A2/">分页查询</a>
</li>
<li>
<a class="" href="/notes/mybatisplus/%E9%80%BB%E8%BE%91%E5%88%A0%E9%99%A4/">逻辑删除</a>
</li>
<li>
<a class="" href="/notes/mybatisplus/%E6%9D%A1%E4%BB%B6%E6%9F%A5%E8%AF%A2/">条件查询</a>
</li>
<li>
<a class="" href="/notes/mybatisplus/%E5%B0%81%E8%A3%85service%E4%BD%BF%E7%94%A8/">封装service使用</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-3907b2cf55ed520ad784e24525c8baa4" type="checkbox"/>
<label class="flex justify-between" for="section-3907b2cf55ed520ad784e24525c8baa4">
<a class="" role="button">Swift</a>
</label>
<ul>
<li>
<a class="" href="/notes/swift/swiftui-%E5%B8%B8%E7%94%A8%E8%A7%86%E5%9B%BE-views/">Swift Ui 常用视图 Views</a>
</li>
<li>
<a class="" href="/notes/swift/swiftui-%E4%BF%A1%E6%81%AF%E8%A7%86%E5%9B%BE-views/">Swift Ui 信息视图 Views</a>
</li>
<li>
<a class="" href="/notes/swift/swiftui-%E5%B1%82%E7%BA%A7%E8%A7%86%E5%9B%BE-views/">Swift Ui 层级视图 Views</a>
</li>
<li>
<a class="" href="/notes/swift/swiftui-%E6%8E%A7%E5%88%B6%E8%A7%86%E5%9B%BE-views/">Swift Ui 控制视图 Views</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-0f70934a6e5284fbc93928c61dfe9c83" type="checkbox"/>
<label class="flex justify-between" for="section-0f70934a6e5284fbc93928c61dfe9c83">
<a class="" role="button">Java</a>
</label>
<ul>
<li>
<a class="" href="/notes/java/arraylist-%E6%89%A9%E5%AE%B9%E8%A7%84%E5%88%99/">Array List 扩容规则</a>
</li>
<li>
<a class="" href="/notes/java/hashmap-%E7%9B%B8%E5%85%B3%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93/">Hash Map 相关学习总结</a>
</li>
<li>
<a class="" href="/notes/java/java-%E5%8F%8D%E5%B0%84/">Java 反射</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-3d1ea9814960db7e996773b67773e705" type="checkbox"/>
<label class="flex justify-between" for="section-3d1ea9814960db7e996773b67773e705">
<a class="" role="button">Java八股</a>
</label>
<ul>
<li>
<a class="" href="/notes/java-%E7%9B%B8%E5%85%B3/%E5%B9%B6%E5%8F%91/">Concurrence</a>
</li>
<li>
<a class="" href="/notes/java-%E7%9B%B8%E5%85%B3/mybatis/">MyBatis</a>
</li>
<li>
<a class="" href="/notes/java-%E7%9B%B8%E5%85%B3/mysql/">MySQL</a>
</li>
<li>
<a class="" href="/notes/java-%E7%9B%B8%E5%85%B3/jvm/">Jvm</a>
</li>
<li>
<a class="" href="/notes/java-%E7%9B%B8%E5%85%B3/redis/">Redis</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-ea55243c547fa272027885b73a74852e" type="checkbox"/>
<label class="flex justify-between" for="section-ea55243c547fa272027885b73a74852e">
<a class="" role="button">嵌入式重点总结</a>
</label>
<ul>
<li>
<a class="" href="/notes/%E5%B5%8C%E5%85%A5%E5%BC%8F%E6%80%BB%E7%BB%93/c/">C 语言相关</a>
</li>
<li>
<a class="" href="/notes/%E5%B5%8C%E5%85%A5%E5%BC%8F%E6%80%BB%E7%BB%93/%E4%B8%AD%E6%96%AD%E7%B3%BB%E7%BB%9F/">中断系统</a>
</li>
<li>
<a class="" href="/notes/%E5%B5%8C%E5%85%A5%E5%BC%8F%E6%80%BB%E7%BB%93/%E5%AE%9A%E6%97%B6%E5%99%A8/">TIM</a>
</li>
<li>
<a class="" href="/notes/%E5%B5%8C%E5%85%A5%E5%BC%8F%E6%80%BB%E7%BB%93/adc/">ADC</a>
</li>
<li>
<a class="" href="/notes/%E5%B5%8C%E5%85%A5%E5%BC%8F%E6%80%BB%E7%BB%93/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98/">嵌入式知识点串烧</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="book-section-flat">
<span>--解决方案--👇</span>
<ul>
<li>
<input class="toggle" id="section-f1d4602254471b9d0da445dd468cd456" type="checkbox"/>
<label class="flex justify-between" for="section-f1d4602254471b9d0da445dd468cd456">
<a class="" role="button">环境配置</a>
</label>
<ul>
<li>
<a class="" href="/solution/environment/apple-m%E7%B3%BB%E5%88%97%E8%8A%AF%E7%89%87%E5%AE%89%E8%A3%85-pyqt/">Apple M系列芯片安装 Pyqt</a>
</li>
<li>
<a class="" href="/solution/environment/docker-%E5%AE%89%E8%A3%85-redis-/">Docker 安装 Redis</a>
</li>
<li>
<a class="" href="/solution/environment/hugo-%E4%B8%BB%E9%A2%98-hugo-book-%E4%B8%AD%E8%8B%B1%E6%96%87%E6%90%9C%E7%B4%A2%E9%85%8D%E7%BD%AE/">Hugo 主题 Hugo Book 中英文搜索配置</a>
</li>
<li>
<a class="" href="/solution/environment/iterm2-oh-my-zsh-%E9%85%8D%E7%BD%AE/">I Term2 Oh My Zsh 配置</a>
</li>
<li>
<a class="" href="/solution/environment/m1-%E8%8A%AF%E7%89%87-docker-%E5%AE%89%E8%A3%85-mysql5.7-/">M1 芯片 Docker 安装 Mysql5.7</a>
</li>
<li>
<a class="" href="/solution/environment/mac-idea-%E5%BF%AB%E6%8D%B7%E9%94%AE%E4%BD%8D/">MAC Idea 快捷键位</a>
</li>
<li>
<a class="" href="/solution/environment/mac-%E5%90%AF%E5%8A%A8%E5%8F%B0%E8%87%AA%E5%AE%9A%E4%B9%89%E8%A1%8C%E5%88%97%E5%B8%83%E5%B1%80/">MAC 启动台自定义行列布局</a>
</li>
<li>
<a class="" href="/solution/environment/%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F/">内网穿透</a>
</li>
<li>
<a class="" href="/solution/environment/%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F%E7%9A%84%E8%87%AA%E5%90%AF%E5%8A%A8%E8%AE%BE%E7%BD%AE/">内网穿透的自启动设置</a>
</li>
</ul>
</li>
<li>
<input class="toggle" id="section-5a76a664ba4855b79d3c1bc77e5b08b1" type="checkbox"/>
<label class="flex justify-between" for="section-5a76a664ba4855b79d3c1bc77e5b08b1">
<a class="" role="button">杂乱问题</a>
</label>
<ul>
<li>
<a class="" href="/solution/problems/brew-%E4%B8%80%E4%BA%9B%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/">Brew 一些常用命令</a>
</li>
<li>
<a class="" href="/solution/problems/docker-%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/">Docker 常用命令</a>
</li>
<li>
<a class="" href="/solution/problems/git-github-%E7%9B%B8%E5%85%B3%E5%91%BD%E4%BB%A4%E6%95%B4%E7%90%86/">Git Git Hub 相关命令整理</a>
</li>
<li>
<a class="" href="/solution/problems/%E9%9D%A2%E8%AF%95%E9%A2%98%E6%89%AB%E7%9B%B2/">面试题扫盲</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="book-section-flat">
<span>一点业余👇</span>
<ul>
</ul>
</li>
<li class="book-section-flat">
<span>--其他记录--👇</span>
<ul>
<li>
<input class="toggle" id="section-9ef4d2063ddc9af7785b193647f22260" type="checkbox"/>
<label class="flex justify-between" for="section-9ef4d2063ddc9af7785b193647f22260">
<a class="" role="button">我和阿刁</a>
</label>
<ul>
<li>
<a class="" href="/daily/ad/%E5%85%B3%E4%BA%8E%E9%98%BF%E5%88%812022%E5%B9%B4%E7%9A%84%E7%94%9F%E6%97%A5%E7%9A%84%E5%B0%8F%E8%AE%BA%E6%96%87/">关于阿刁2022年的生日的小论文</a>
</li>
<li>
<a class="" href="/daily/ad/%E5%85%B3%E4%BA%8E%E9%98%BF%E5%88%81%E7%9A%842021%E5%B9%B4%E5%BA%A6%E6%80%BB%E7%BB%93/">关于阿刁的2021年度总结</a>
</li>
<li>
<a class="" href="/daily/ad/%E5%85%B3%E4%BA%8E%E9%98%BF%E5%88%81%E7%9A%842022%E5%B9%B4%E5%BA%A6%E6%80%BB%E7%BB%93/">关于阿刁的2022年度总结</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
<script>(function(){var e=document.querySelector("aside .book-menu-content");addEventListener("beforeunload",function(){localStorage.setItem("menu.scrollTop",e.scrollTop)}),e.scrollTop=localStorage.getItem("menu.scrollTop")})()</script>
</div>
</aside>
<div class="book-page">
<header class="book-header">
<div class="flex align-center justify-between">
<label for="menu-control">
<img alt="Menu" class="book-icon" src="/svg/menu.svg"/>
</label>
<strong>创建型模式</strong>
<label for="toc-control">
<img alt="Table of Contents" class="book-icon" src="/svg/toc.svg"/>
</label>
</div>
<aside class="hidden clearfix">
<nav id="TableOfContents">
<ul>
<li><a href="#创建型模式">创建型模式</a>
<ul>
<li><a href="#1-单例设计模式">1 单例设计模式</a>
<ul>
<li><a href="#11-概述">1.1 概述</a></li>
<li><a href="#12-结构">1.2 结构</a></li>
<li><a href="#13-案例实现">1.3 案例实现</a>
<ul>
<li><a href="#121-饿汉式">1.2.1 饿汉式</a></li>
<li><a href="#122-懒汉式">1.2.2 懒汉式</a></li>
<li><a href="#123-枚举方式">1.2.3 枚举方式</a></li>
</ul>
</li>
<li><a href="#14-jdk源码解析-runtime类">1.4 JDK源码解析-Runtime类</a></li>
<li><a href="#15-存在的问题">1.5 存在的问题</a>
<ul>
<li><a href="#151-问题演示">1.5.1 问题演示</a></li>
<li><a href="#152-问题的解决">1.5.2 问题的解决</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#2-工厂模式">2 工厂模式</a>
<ul>
<li><a href="#21-概述">2.1 概述</a></li>
<li><a href="#22-简单工厂模式">2.2 简单工厂模式</a>
<ul>
<li><a href="#221-概念">2.2.1 概念</a></li>
<li><a href="#222-结构">2.2.2 结构</a></li>
<li><a href="#223-实现">2.2.3 实现</a></li>
<li><a href="#224-扩展">2.2.4 扩展</a></li>
</ul>
</li>
<li><a href="#23-工厂方法模式">2.3 工厂方法模式</a>
<ul>
<li><a href="#231-概念">2.3.1 概念</a></li>
<li><a href="#232-结构">2.3.2 结构</a></li>
<li><a href="#233-实现">2.3.3 实现</a></li>
</ul>
</li>
<li><a href="#24-抽象工厂模式">2.4 抽象工厂模式</a>
<ul>
<li><a href="#241-概念">2.4.1 概念</a></li>
<li><a href="#242-结构">2.4.2 结构</a></li>
<li><a href="#243-实现">2.4.3 实现</a></li>
<li><a href="#244-使用场景">2.4.4 使用场景</a></li>
</ul>
</li>
<li><a href="#25-模式扩展">2.5 模式扩展</a></li>
<li><a href="#26-jdk源码解析-collectioniterator方法">2.6 JDK源码解析-Collection.iterator方法</a></li>
</ul>
</li>
<li><a href="#3-原型模式">3 原型模式</a>
<ul>
<li><a href="#31-概述">3.1 概述</a></li>
<li><a href="#32-结构">3.2 结构</a></li>
<li><a href="#33-案例">3.3 案例</a></li>
<li><a href="#34-使用场景">3.4 使用场景</a></li>
<li><a href="#35-扩展深克隆">3.5 扩展（深克隆）</a></li>
</ul>
</li>
<li><a href="#4-建造者模式">4 建造者模式</a>
<ul>
<li><a href="#41-概述">4.1 概述</a></li>
<li><a href="#42-结构">4.2 结构</a></li>
<li><a href="#43-实例">4.3 实例</a></li>
<li><a href="#44-使用场景">4.4 使用场景</a></li>
<li><a href="#45-模式扩展">4.5 模式扩展</a></li>
<li><a href="#46-创建者模式对比">4.6 创建者模式对比</a>
<ul>
<li><a href="#461-工厂方法模式vs建造者模式">4.6.1 工厂方法模式VS建造者模式</a></li>
<li><a href="#462-抽象工厂模式vs建造者模式">4.6.2 抽象工厂模式VS建造者模式</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
</aside>
</header>
<article class="markdown"><h1 id="创建型模式">
  创建型模式
  <a class="anchor" href="#%e5%88%9b%e5%bb%ba%e5%9e%8b%e6%a8%a1%e5%bc%8f">#</a>
</h1>
<p>创建型模式的主要关注点是“怎样创建对象？”，它的主要特点是“将对象的创建与使用分离”。</p>
<p>这样可以降低系统的耦合度，并且使用者不需要关注对象的创建细节。</p>
<h2 id="1-单例设计模式">
  1 单例设计模式
  <a class="anchor" href="#1-%e5%8d%95%e4%be%8b%e8%ae%be%e8%ae%a1%e6%a8%a1%e5%bc%8f">#</a>
</h2>
<h3 id="11-概述">
  1.1 概述
  <a class="anchor" href="#11-%e6%a6%82%e8%bf%b0">#</a>
</h3>
<p>单例模式（Singleton Pattern）是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式，它提供了一种创建对象的最佳方式。</p>
<p>这种模式涉及到一个单一的类，该类负责创建自己的对象，同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式，可以直接访问，不需要实例化该类的对象。</p>
<h3 id="12-结构">
  1.2 结构
  <a class="anchor" href="#12-%e7%bb%93%e6%9e%84">#</a>
</h3>
<p>单例模式的主要有以下角色：</p>
<ul>
<li>单例类。只能创建一个实例的类</li>
<li>访问类。使用单例类</li>
</ul>
<h3 id="13-案例实现">
  1.3 案例实现
  <a class="anchor" href="#13-%e6%a1%88%e4%be%8b%e5%ae%9e%e7%8e%b0">#</a>
</h3>
<blockquote>
<p>单例设计模式分类两种：</p>
<p>​	饿汉式：类加载就会导致该单实例对象被创建</p>
<p>​	懒汉式：类加载不会导致该单实例对象被创建，而是首次使用该对象时才会创建</p>
</blockquote>
<h4 id="121-饿汉式">
  1.2.1 饿汉式
  <a class="anchor" href="#121-%e9%a5%bf%e6%b1%89%e5%bc%8f">#</a>
</h4>
<p><strong>方式1（静态变量方式）</strong></p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> * 饿汉式
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> *      静态变量创建类的对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Singleton</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//私有构造方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">Singleton</span><span style="color:#f92672">()</span> <span style="color:#f92672">{}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//在成员位置创建该类的对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> Singleton instance <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Singleton<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//对外提供静态方法获取该对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> Singleton <span style="color:#a6e22e">getInstance</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><font color="red">说明：</font></p>
<p>​	该方式在成员位置声明Singleton类型的静态变量，并创建Singleton类的对象instance。instance对象是随着类的加载而创建的。如果该对象足够大的话，而一直没有使用就会造成内存的浪费。</p>
<p><strong>方式2（静态代码块方式）</strong></p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> * 恶汉式
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> *      在静态代码块中创建该类对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Singleton</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//私有构造方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">Singleton</span><span style="color:#f92672">()</span> <span style="color:#f92672">{}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//在成员位置创建该类的对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> Singleton instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">static</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        instance <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Singleton<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//对外提供静态方法获取该对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> Singleton <span style="color:#a6e22e">getInstance</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><font color="red">说明：</font></p>
<p>​	该方式在成员位置声明Singleton类型的静态变量，而对象的创建是在静态代码块中，也是对着类的加载而创建。所以和饿汉式的方式1基本上一样，当然该方式也存在内存浪费问题。</p>
<h4 id="122-懒汉式">
  1.2.2 懒汉式
  <a class="anchor" href="#122-%e6%87%92%e6%b1%89%e5%bc%8f">#</a>
</h4>
<p><strong>方式1（线程不安全）</strong></p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> * 懒汉式
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> *  线程不安全
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Singleton</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//私有构造方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">Singleton</span><span style="color:#f92672">()</span> <span style="color:#f92672">{}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//在成员位置创建该类的对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> Singleton instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//对外提供静态方法获取该对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> Singleton <span style="color:#a6e22e">getInstance</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span>instance <span style="color:#f92672">==</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            instance <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Singleton<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><font color="red">说明：</font></p>
<p>​	从上面代码我们可以看出该方式在成员位置声明Singleton类型的静态变量，并没有进行对象的赋值操作，那么什么时候赋值的呢？当调用getInstance()方法获取Singleton类的对象的时候才创建Singleton类的对象，这样就实现了懒加载的效果。但是，如果是多线程环境，会出现线程安全问题。</p>
<p><strong>懒汉式-方式2（线程安全）</strong></p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> * 懒汉式
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> *  线程安全
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Singleton</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//私有构造方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">Singleton</span><span style="color:#f92672">()</span> <span style="color:#f92672">{}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//在成员位置创建该类的对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> Singleton instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//对外提供静态方法获取该对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">synchronized</span> Singleton <span style="color:#a6e22e">getInstance</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span>instance <span style="color:#f92672">==</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            instance <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Singleton<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><font color="red">说明：</font></p>
<p>​	该方式也实现了懒加载效果，同时又解决了线程安全问题。但是在getInstance()方法上添加了synchronized关键字，导致该方法的执行效果特别低。从上面代码我们可以看出，其实就是在初始化instance的时候才会出现线程安全问题，一旦初始化完成就不存在了。</p>
<p><strong>懒汉式-方式3（双重检查锁）</strong></p>
<p>再来讨论一下懒汉模式中加锁的问题，对于 <code>getInstance()</code> 方法来说，绝大部分的操作都是读操作，读操作是线程安全的，所以我们没必让每个线程必须持有锁才能调用该方法，我们需要调整加锁的时机。由此也产生了一种新的实现模式：双重检查锁模式</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> * 双重检查方式
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Singleton</span> <span style="color:#f92672">{</span> 
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//私有构造方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">Singleton</span><span style="color:#f92672">()</span> <span style="color:#f92672">{}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> Singleton instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>   <span style="color:#75715e">//对外提供静态方法获取该对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> Singleton <span style="color:#a6e22e">getInstance</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>		<span style="color:#75715e">//第一次判断，如果instance不为null，不进入抢锁阶段，直接返回实例
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span>instance <span style="color:#f92672">==</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">synchronized</span> <span style="color:#f92672">(</span>Singleton<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                <span style="color:#75715e">//抢到锁之后再次判断是否为null
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>                <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span>instance <span style="color:#f92672">==</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                    instance <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Singleton<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>双重检查锁模式是一种非常好的单例实现模式，解决了单例、性能、线程安全问题，上面的双重检测锁模式看上去完美无缺，其实是存在问题，在多线程的情况下，可能会出现空指针问题，出现问题的原因是JVM在实例化对象的时候会进行优化和指令重排序操作。</p>
<p>要解决双重检查锁模式带来空指针异常的问题，只需要使用 <code>volatile</code> 关键字, <code>volatile</code> 关键字可以保证可见性和有序性。</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> * 双重检查方式
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Singleton</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//私有构造方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">Singleton</span><span style="color:#f92672">()</span> <span style="color:#f92672">{}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">volatile</span> Singleton instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>   <span style="color:#75715e">//对外提供静态方法获取该对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> Singleton <span style="color:#a6e22e">getInstance</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>		<span style="color:#75715e">//第一次判断，如果instance不为null，不进入抢锁阶段，直接返回实际
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span>instance <span style="color:#f92672">==</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">synchronized</span> <span style="color:#f92672">(</span>Singleton<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                <span style="color:#75715e">//抢到锁之后再次判断是否为空
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>                <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span>instance <span style="color:#f92672">==</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                    instance <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Singleton<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><font color="red">小结：</font></p>
<p><strong>添加 <code>volatile</code> 关键字之后的双重检查锁模式是一种比较好的单例实现模式，能够保证在多线程的情况下线程安全也不会有性能问题。</strong></p>
<p><strong>懒汉式-方式4（静态内部类方式）</strong></p>
<p>静态内部类单例模式中实例由内部类创建，由于 JVM 在加载外部类的过程中, 是不会加载静态内部类的, 只有内部类的属性/方法被调用时才会被加载, 并初始化其静态属性。静态属性由于被 <code>static</code> 修饰，保证只被实例化一次，并且严格保证实例化顺序。</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> * 静态内部类方式
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Singleton</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//私有构造方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">Singleton</span><span style="color:#f92672">()</span> <span style="color:#f92672">{}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SingletonHolder</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">final</span> Singleton INSTANCE <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Singleton<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//对外提供静态方法获取该对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> Singleton <span style="color:#a6e22e">getInstance</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> SingletonHolder<span style="color:#f92672">.</span><span style="color:#a6e22e">INSTANCE</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><font color="red">说明：</font></p>
<p>​	第一次加载Singleton类时不会去初始化INSTANCE，只有第一次调用getInstance，虚拟机加载SingletonHolder</p>
<p>并初始化INSTANCE，这样不仅能确保线程安全，也能保证 Singleton 类的唯一性。</p>
<p><font color="red">小结：</font></p>
<p>​	静态内部类单例模式是一种优秀的单例模式，是开源项目中比较常用的一种单例模式。在没有加任何锁的情况下，保证了多线程下的安全，并且没有任何性能影响和空间的浪费。</p>
<h4 id="123-枚举方式">
  1.2.3 枚举方式
  <a class="anchor" href="#123-%e6%9e%9a%e4%b8%be%e6%96%b9%e5%bc%8f">#</a>
</h4>
<p>枚举类实现单例模式是极力推荐的单例实现模式，因为枚举类型是线程安全的，并且只会装载一次，设计者充分的利用了枚举的这个特性来实现单例模式，枚举的写法非常简单，而且枚举类型是所用单例实现中唯一一种不会被破坏的单例实现模式。</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> * 枚举方式
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"> */</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">enum</span> Singleton <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    INSTANCE<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><font color="red">说明：</font></p>
<p>​	枚举方式属于恶汉式方式。</p>
<h3 id="14-jdk源码解析-runtime类">
  1.4 JDK源码解析-Runtime类
  <a class="anchor" href="#14-jdk%e6%ba%90%e7%a0%81%e8%a7%a3%e6%9e%90-runtime%e7%b1%bb">#</a>
</h3>
<p>Runtime类就是使用的单例设计模式。</p>
<ol>
<li>
<p>通过源代码查看使用的是哪儿种单例模式</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Runtime</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> Runtime currentRuntime <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Runtime<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">     * Returns the runtime object associated with the current Java application.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">     * Most of the methods of class &lt;code&gt;Runtime&lt;/code&gt; are instance
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">     * methods and must be invoked with respect to the current runtime object.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">     *
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">     * @return  the &lt;code&gt;Runtime&lt;/code&gt; object associated with the current
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">     *          Java application.
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">     */</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> Runtime <span style="color:#a6e22e">getRuntime</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> currentRuntime<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">/** Don't let anyone else instantiate this class */</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">Runtime</span><span style="color:#f92672">()</span> <span style="color:#f92672">{}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">...</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>从上面源代码中可以看出Runtime类使用的是恶汉式（静态属性）方式来实现单例模式的。</p>
</li>
<li>
<p>使用Runtime类中的方法</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">RuntimeDemo</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> IOException <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//获取Runtime类对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Runtime runtime <span style="color:#f92672">=</span> Runtime<span style="color:#f92672">.</span><span style="color:#a6e22e">getRuntime</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//返回 Java 虚拟机中的内存总量。
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>runtime<span style="color:#f92672">.</span><span style="color:#a6e22e">totalMemory</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//返回 Java 虚拟机试图使用的最大内存量。
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>runtime<span style="color:#f92672">.</span><span style="color:#a6e22e">maxMemory</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//创建一个新的进程执行指定的字符串命令，返回进程对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Process process <span style="color:#f92672">=</span> runtime<span style="color:#f92672">.</span><span style="color:#a6e22e">exec</span><span style="color:#f92672">(</span><span style="color:#e6db74">"ipconfig"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//获取命令执行后的结果，通过输入流获取
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        InputStream inputStream <span style="color:#f92672">=</span> process<span style="color:#f92672">.</span><span style="color:#a6e22e">getInputStream</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">byte</span><span style="color:#f92672">[]</span> arr <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#66d9ef">byte</span><span style="color:#f92672">[</span><span style="color:#ae81ff">1024</span> <span style="color:#f92672">*</span> <span style="color:#ae81ff">1024</span><span style="color:#f92672">*</span> <span style="color:#ae81ff">100</span><span style="color:#f92672">];</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">int</span> b <span style="color:#f92672">=</span> inputStream<span style="color:#f92672">.</span><span style="color:#a6e22e">read</span><span style="color:#f92672">(</span>arr<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> String<span style="color:#f92672">(</span>arr<span style="color:#f92672">,</span><span style="color:#ae81ff">0</span><span style="color:#f92672">,</span>b<span style="color:#f92672">,</span><span style="color:#e6db74">"gbk"</span><span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
</li>
</ol>
<h3 id="15-存在的问题">
  1.5 存在的问题
  <a class="anchor" href="#15-%e5%ad%98%e5%9c%a8%e7%9a%84%e9%97%ae%e9%a2%98">#</a>
</h3>
<h4 id="151-问题演示">
  1.5.1 问题演示
  <a class="anchor" href="#151-%e9%97%ae%e9%a2%98%e6%bc%94%e7%a4%ba">#</a>
</h4>
<p>破坏单例模式：</p>
<p>使上面定义的单例类（Singleton）可以创建多个对象，枚举方式除外。有两种方式，分别是序列化和反射。</p>
<ul>
<li>
<p>序列化反序列化</p>
<p><strong>Singleton类：</strong></p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Singleton</span> <span style="color:#66d9ef">implements</span> Serializable <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//私有构造方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">Singleton</span><span style="color:#f92672">()</span> <span style="color:#f92672">{}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SingletonHolder</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">final</span> Singleton INSTANCE <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Singleton<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//对外提供静态方法获取该对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> Singleton <span style="color:#a6e22e">getInstance</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> SingletonHolder<span style="color:#f92672">.</span><span style="color:#a6e22e">INSTANCE</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><strong>Test类：</strong></p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Test</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> Exception <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//往文件中写对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#75715e">//writeObject2File();
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#75715e">//从文件中读取对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Singleton s1 <span style="color:#f92672">=</span> readObjectFromFile<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        Singleton s2 <span style="color:#f92672">=</span> readObjectFromFile<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//判断两个反序列化后的对象是否是同一个对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>s1 <span style="color:#f92672">==</span> s2<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> Singleton <span style="color:#a6e22e">readObjectFromFile</span><span style="color:#f92672">()</span> <span style="color:#66d9ef">throws</span> Exception <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//创建对象输入流对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        ObjectInputStream ois <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ObjectInputStream<span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> FileInputStream<span style="color:#f92672">(</span><span style="color:#e6db74">"C:\\Users\\Think\\Desktop\\a.txt"</span><span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//第一个读取Singleton对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Singleton instance <span style="color:#f92672">=</span> <span style="color:#f92672">(</span>Singleton<span style="color:#f92672">)</span> ois<span style="color:#f92672">.</span><span style="color:#a6e22e">readObject</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">writeObject2File</span><span style="color:#f92672">()</span> <span style="color:#66d9ef">throws</span> Exception <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//获取Singleton类的对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Singleton instance <span style="color:#f92672">=</span> Singleton<span style="color:#f92672">.</span><span style="color:#a6e22e">getInstance</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//创建对象输出流
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        ObjectOutputStream oos <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ObjectOutputStream<span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> FileOutputStream<span style="color:#f92672">(</span><span style="color:#e6db74">"C:\\Users\\Think\\Desktop\\a.txt"</span><span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//将instance对象写出到文件中
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        oos<span style="color:#f92672">.</span><span style="color:#a6e22e">writeObject</span><span style="color:#f92672">(</span>instance<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<blockquote>
<p>上面代码运行结果是<code>false</code>，表明序列化和反序列化已经破坏了单例设计模式。</p>
</blockquote>
</li>
<li>
<p>反射</p>
<p><strong>Singleton类：</strong></p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Singleton</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//私有构造方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">Singleton</span><span style="color:#f92672">()</span> <span style="color:#f92672">{}</span>
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">volatile</span> Singleton instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//对外提供静态方法获取该对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> Singleton <span style="color:#a6e22e">getInstance</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span>instance <span style="color:#f92672">!=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">synchronized</span> <span style="color:#f92672">(</span>Singleton<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span>instance <span style="color:#f92672">!=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">return</span> instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>            instance <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Singleton<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><strong>Test类：</strong></p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Test</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> Exception <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//获取Singleton类的字节码对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Class clazz <span style="color:#f92672">=</span> Singleton<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//获取Singleton类的私有无参构造方法对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Constructor constructor <span style="color:#f92672">=</span> clazz<span style="color:#f92672">.</span><span style="color:#a6e22e">getDeclaredConstructor</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//取消访问检查
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        constructor<span style="color:#f92672">.</span><span style="color:#a6e22e">setAccessible</span><span style="color:#f92672">(</span><span style="color:#66d9ef">true</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//创建Singleton类的对象s1
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Singleton s1 <span style="color:#f92672">=</span> <span style="color:#f92672">(</span>Singleton<span style="color:#f92672">)</span> constructor<span style="color:#f92672">.</span><span style="color:#a6e22e">newInstance</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//创建Singleton类的对象s2
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Singleton s2 <span style="color:#f92672">=</span> <span style="color:#f92672">(</span>Singleton<span style="color:#f92672">)</span> constructor<span style="color:#f92672">.</span><span style="color:#a6e22e">newInstance</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//判断通过反射创建的两个Singleton对象是否是同一个对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>s1 <span style="color:#f92672">==</span> s2<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<blockquote>
<p>上面代码运行结果是<code>false</code>，表明序列化和反序列化已经破坏了单例设计模式</p>
</blockquote>
</li>
</ul>
<blockquote>
<p><font color="red">注意：</font>枚举方式不会出现这两个问题。</p>
</blockquote>
<h4 id="152-问题的解决">
  1.5.2 问题的解决
  <a class="anchor" href="#152-%e9%97%ae%e9%a2%98%e7%9a%84%e8%a7%a3%e5%86%b3">#</a>
</h4>
<ul>
<li>
<p>序列化、反序列方式破坏单例模式的解决方法</p>
<p>在Singleton类中添加<code>readResolve()</code>方法，在反序列化时被反射调用，如果定义了这个方法，就返回这个方法的值，如果没有定义，则返回新new出来的对象。</p>
<p><strong>Singleton类：</strong></p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Singleton</span> <span style="color:#66d9ef">implements</span> Serializable <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//私有构造方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">Singleton</span><span style="color:#f92672">()</span> <span style="color:#f92672">{}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SingletonHolder</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">final</span> Singleton INSTANCE <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Singleton<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//对外提供静态方法获取该对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> Singleton <span style="color:#a6e22e">getInstance</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> SingletonHolder<span style="color:#f92672">.</span><span style="color:#a6e22e">INSTANCE</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">/**
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">     * 下面是为了解决序列化反序列化破解单例模式
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">     */</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> Object <span style="color:#a6e22e">readResolve</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> SingletonHolder<span style="color:#f92672">.</span><span style="color:#a6e22e">INSTANCE</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><strong>源码解析：</strong></p>
<p>ObjectInputStream类</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">final</span> Object <span style="color:#a6e22e">readObject</span><span style="color:#f92672">()</span> <span style="color:#66d9ef">throws</span> IOException<span style="color:#f92672">,</span> ClassNotFoundException<span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">...</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// if nested read, passHandle contains handle of enclosing object
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">int</span> outerHandle <span style="color:#f92672">=</span> passHandle<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">try</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        Object obj <span style="color:#f92672">=</span> readObject0<span style="color:#f92672">(</span><span style="color:#66d9ef">false</span><span style="color:#f92672">);</span><span style="color:#75715e">//重点查看readObject0方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#f92672">.....</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">private</span> Object <span style="color:#a6e22e">readObject0</span><span style="color:#f92672">(</span><span style="color:#66d9ef">boolean</span> unshared<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> IOException <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">...</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">try</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>		<span style="color:#66d9ef">switch</span> <span style="color:#f92672">(</span>tc<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>			<span style="color:#f92672">...</span>
</span></span><span style="display:flex;"><span>			<span style="color:#66d9ef">case</span> TC_OBJECT<span style="color:#f92672">:</span>
</span></span><span style="display:flex;"><span>				<span style="color:#66d9ef">return</span> checkResolve<span style="color:#f92672">(</span>readOrdinaryObject<span style="color:#f92672">(</span>unshared<span style="color:#f92672">));</span><span style="color:#75715e">//重点查看readOrdinaryObject方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>			<span style="color:#f92672">...</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span> <span style="color:#66d9ef">finally</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        depth<span style="color:#f92672">--;</span>
</span></span><span style="display:flex;"><span>        bin<span style="color:#f92672">.</span><span style="color:#a6e22e">setBlockDataMode</span><span style="color:#f92672">(</span>oldMode<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>    
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">private</span> Object <span style="color:#a6e22e">readOrdinaryObject</span><span style="color:#f92672">(</span><span style="color:#66d9ef">boolean</span> unshared<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> IOException <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>	<span style="color:#f92672">...</span>
</span></span><span style="display:flex;"><span>	<span style="color:#75715e">//isInstantiable 返回true，执行 desc.newInstance()，通过反射创建新的单例类，
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    obj <span style="color:#f92672">=</span> desc<span style="color:#f92672">.</span><span style="color:#a6e22e">isInstantiable</span><span style="color:#f92672">()</span> <span style="color:#f92672">?</span> desc<span style="color:#f92672">.</span><span style="color:#a6e22e">newInstance</span><span style="color:#f92672">()</span> <span style="color:#f92672">:</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">;</span> 
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">...</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// 在Singleton类中添加 readResolve 方法后 desc.hasReadResolveMethod() 方法执行结果为true
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">if</span> <span style="color:#f92672">(</span>obj <span style="color:#f92672">!=</span> <span style="color:#66d9ef">null</span> <span style="color:#f92672">&amp;&amp;</span> handles<span style="color:#f92672">.</span><span style="color:#a6e22e">lookupException</span><span style="color:#f92672">(</span>passHandle<span style="color:#f92672">)</span> <span style="color:#f92672">==</span> <span style="color:#66d9ef">null</span> <span style="color:#f92672">&amp;&amp;</span> desc<span style="color:#f92672">.</span><span style="color:#a6e22e">hasReadResolveMethod</span><span style="color:#f92672">())</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    	<span style="color:#75715e">// 通过反射调用 Singleton 类中的 readResolve 方法，将返回值赋值给rep变量
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    	<span style="color:#75715e">// 这样多次调用ObjectInputStream类中的readObject方法，继而就会调用我们定义的readResolve方法，所以返回的是同一个对象。
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    	Object rep <span style="color:#f92672">=</span> desc<span style="color:#f92672">.</span><span style="color:#a6e22e">invokeReadResolve</span><span style="color:#f92672">(</span>obj<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>     	<span style="color:#f92672">...</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> obj<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
</li>
<li>
<p>反射方式破解单例的解决方法</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Singleton</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//私有构造方法
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">Singleton</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">/*
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">           反射破解单例模式需要添加的代码
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">        */</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span>instance <span style="color:#f92672">!=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">throw</span> <span style="color:#66d9ef">new</span> RuntimeException<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">volatile</span> Singleton instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//对外提供静态方法获取该对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> Singleton <span style="color:#a6e22e">getInstance</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span>instance <span style="color:#f92672">!=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">synchronized</span> <span style="color:#f92672">(</span>Singleton<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span>instance <span style="color:#f92672">!=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                <span style="color:#66d9ef">return</span> instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>            instance <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Singleton<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> instance<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><font color="red">说明:</font></p>
<p>​	这种方式比较好理解。当通过反射方式调用构造方法进行创建创建时，直接抛异常。不运行此中操作。</p>
</li>
</ul>
<h2 id="2-工厂模式">
  2 工厂模式
  <a class="anchor" href="#2-%e5%b7%a5%e5%8e%82%e6%a8%a1%e5%bc%8f">#</a>
</h2>
<h3 id="21-概述">
  2.1 概述
  <a class="anchor" href="#21-%e6%a6%82%e8%bf%b0">#</a>
</h3>
<p>需求：设计一个咖啡店点餐系统。</p>
<p>设计一个咖啡类（Coffee），并定义其两个子类（美式咖啡【AmericanCoffee】和拿铁咖啡【LatteCoffee】）；再设计一个咖啡店类（CoffeeStore），咖啡店具有点咖啡的功能。</p>
<p>具体类的设计如下：</p>
<img src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211291439594.png" style="zoom: 67%;"/>
<p>在java中，万物皆对象，这些对象都需要创建，如果创建的时候直接new该对象，就会对该对象耦合严重，假如我们要更换对象，所有new对象的地方都需要修改一遍，这显然违背了软件设计的开闭原则。如果我们使用工厂来生产对象，我们就只和工厂打交道就可以了，彻底和对象解耦，如果要更换对象，直接在工厂里更换该对象即可，达到了与对象解耦的目的；所以说，工厂模式最大的优点就是：<strong>解耦</strong>。</p>
<h3 id="22-简单工厂模式">
  2.2 简单工厂模式
  <a class="anchor" href="#22-%e7%ae%80%e5%8d%95%e5%b7%a5%e5%8e%82%e6%a8%a1%e5%bc%8f">#</a>
</h3>
<h4 id="221-概念">
  2.2.1 概念
  <a class="anchor" href="#221-%e6%a6%82%e5%bf%b5">#</a>
</h4>
<p>简单工厂不是一种设计模式，反而比较像是一种编程习惯。</p>
<h4 id="222-结构">
  2.2.2 结构
  <a class="anchor" href="#222-%e7%bb%93%e6%9e%84">#</a>
</h4>
<p>简单工厂包含如下角色：</p>
<ul>
<li>抽象产品 ：定义了产品的规范，描述了产品的主要特性和功能。</li>
<li>具体产品 ：实现或者继承抽象产品的子类</li>
<li>具体工厂 ：提供了创建产品的方法，调用者通过该方法来获取产品。</li>
</ul>
<h4 id="223-实现">
  2.2.3 实现
  <a class="anchor" href="#223-%e5%ae%9e%e7%8e%b0">#</a>
</h4>
<p>现在使用简单工厂对上面案例进行改进，类图如下：</p>
<img src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211291523279.png" style="zoom:70%;"/>
<p>工厂类代码如下：</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SimpleCoffeeFactory</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Coffee <span style="color:#a6e22e">createCoffee</span><span style="color:#f92672">(</span>String type<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        Coffee coffee <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span><span style="color:#e6db74">"americano"</span><span style="color:#f92672">.</span><span style="color:#a6e22e">equals</span><span style="color:#f92672">(</span>type<span style="color:#f92672">))</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            coffee <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> AmericanoCoffee<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span> <span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span><span style="color:#e6db74">"latte"</span><span style="color:#f92672">.</span><span style="color:#a6e22e">equals</span><span style="color:#f92672">(</span>type<span style="color:#f92672">))</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            coffee <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> LatteCoffee<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> coffee<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>工厂（factory）处理创建对象的细节，一旦有了SimpleCoffeeFactory，CoffeeStore类中的orderCoffee()就变成此对象的客户，后期如果需要Coffee对象直接从工厂中获取即可。这样也就解除了和Coffee实现类的耦合，同时又产生了新的耦合，CoffeeStore对象和SimpleCoffeeFactory工厂对象的耦合，工厂对象和商品对象的耦合。</p>
<p>后期如果再加新品种的咖啡，我们势必要需求修改SimpleCoffeeFactory的代码，违反了开闭原则。工厂类的客户端可能有很多，比如创建美团外卖等，这样只需要修改工厂类的代码，省去其他的修改操作。</p>
<p><strong>优点：</strong></p>
<p>封装了创建对象的过程，可以通过参数直接获取对象。把对象的创建和业务逻辑层分开，这样以后就避免了修改客户代码，如果要实现新产品直接修改工厂类，而不需要在原代码中修改，这样就降低了客户代码修改的可能性，更加容易扩展。</p>
<p><strong>缺点：</strong></p>
<p>增加新产品时还是需要修改工厂类的代码，违背了“开闭原则”。</p>
<h4 id="224-扩展">
  2.2.4 扩展
  <a class="anchor" href="#224-%e6%89%a9%e5%b1%95">#</a>
</h4>
<p><strong>静态工厂</strong></p>
<p>在开发中也有一部分人将工厂类中的创建对象的功能定义为静态的，这个就是静态工厂模式，它也不是23种设计模式中的。代码如下：</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">SimpleCoffeeFactory</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> Coffee <span style="color:#a6e22e">createCoffee</span><span style="color:#f92672">(</span>String type<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        Coffee coffee <span style="color:#f92672">=</span> <span style="color:#66d9ef">null</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span><span style="color:#e6db74">"americano"</span><span style="color:#f92672">.</span><span style="color:#a6e22e">equals</span><span style="color:#f92672">(</span>type<span style="color:#f92672">))</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            coffee <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> AmericanoCoffee<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span> <span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span><span style="color:#f92672">(</span><span style="color:#e6db74">"latte"</span><span style="color:#f92672">.</span><span style="color:#a6e22e">equals</span><span style="color:#f92672">(</span>type<span style="color:#f92672">))</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            coffee <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> LatteCoffee<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> coffe<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<h3 id="23-工厂方法模式">
  2.3 工厂方法模式
  <a class="anchor" href="#23-%e5%b7%a5%e5%8e%82%e6%96%b9%e6%b3%95%e6%a8%a1%e5%bc%8f">#</a>
</h3>
<p>针对上例中的缺点，使用工厂方法模式就可以完美的解决，完全遵循开闭原则。</p>
<h4 id="231-概念">
  2.3.1 概念
  <a class="anchor" href="#231-%e6%a6%82%e5%bf%b5">#</a>
</h4>
<p>定义一个用于创建对象的接口，让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类。</p>
<h4 id="232-结构">
  2.3.2 结构
  <a class="anchor" href="#232-%e7%bb%93%e6%9e%84">#</a>
</h4>
<p>工厂方法模式的主要角色：</p>
<ul>
<li>抽象工厂（Abstract Factory）：提供了创建产品的接口，调用者通过它访问具体工厂的工厂方法来创建产品。</li>
<li>具体工厂（ConcreteFactory）：主要是实现抽象工厂中的抽象方法，完成具体产品的创建。</li>
<li>抽象产品（Product）：定义了产品的规范，描述了产品的主要特性和功能。</li>
<li>具体产品（ConcreteProduct）：实现了抽象产品角色所定义的接口，由具体工厂来创建，它同具体工厂之间一一对应。</li>
</ul>
<h4 id="233-实现">
  2.3.3 实现
  <a class="anchor" href="#233-%e5%ae%9e%e7%8e%b0">#</a>
</h4>
<p>使用工厂方法模式对上例进行改进，类图如下：</p>
<img src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211291523281.png" style="zoom:70%;"/>
<p>代码如下：</p>
<p>抽象工厂：</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">interface</span> <span style="color:#a6e22e">CoffeeFactory</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    Coffee <span style="color:#a6e22e">createCoffee</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>具体工厂：</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">LatteCoffeeFactory</span> <span style="color:#66d9ef">implements</span> CoffeeFactory <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Coffee <span style="color:#a6e22e">createCoffee</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> LatteCoffee<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">AmericanCoffeeFactory</span> <span style="color:#66d9ef">implements</span> CoffeeFactory <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Coffee <span style="color:#a6e22e">createCoffee</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> AmericanCoffee<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>咖啡店类：</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">CoffeeStore</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> CoffeeFactory factory<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">CoffeeStore</span><span style="color:#f92672">(</span>CoffeeFactory factory<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">factory</span> <span style="color:#f92672">=</span> factory<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Coffee <span style="color:#a6e22e">orderCoffee</span><span style="color:#f92672">(</span>String type<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        Coffee coffee <span style="color:#f92672">=</span> factory<span style="color:#f92672">.</span><span style="color:#a6e22e">createCoffee</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        coffee<span style="color:#f92672">.</span><span style="color:#a6e22e">addMilk</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        coffee<span style="color:#f92672">.</span><span style="color:#a6e22e">addsugar</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> coffee<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>从以上的编写的代码可以看到，要增加产品类时也要相应地增加工厂类，不需要修改工厂类的代码了，这样就解决了简单工厂模式的缺点。</p>
<p>工厂方法模式是简单工厂模式的进一步抽象。由于使用了多态性，工厂方法模式保持了简单工厂模式的优点，而且克服了它的缺点。</p>
<p><strong>优点：</strong></p>
<ul>
<li>用户只需要知道具体工厂的名称就可得到所要的产品，无须知道产品的具体创建过程；</li>
<li>在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类，无须对原工厂进行任何修改，满足开闭原则；</li>
</ul>
<p><strong>缺点：</strong></p>
<ul>
<li>每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类，这增加了系统的复杂度。</li>
</ul>
<h3 id="24-抽象工厂模式">
  2.4 抽象工厂模式
  <a class="anchor" href="#24-%e6%8a%bd%e8%b1%a1%e5%b7%a5%e5%8e%82%e6%a8%a1%e5%bc%8f">#</a>
</h3>
<p>前面介绍的工厂方法模式中考虑的是一类产品的生产，如畜牧场只养动物、电视机厂只生产电视机、传智播客只培养计算机软件专业的学生等。</p>
<p>这些工厂只生产同种类产品，同种类产品称为同等级产品，也就是说：工厂方法模式只考虑生产同等级的产品，但是在现实生活中许多工厂是综合型的工厂，能生产多等级（种类） 的产品，如电器厂既生产电视机又生产洗衣机或空调，大学既有软件专业又有生物专业等。</p>
<p>本节要介绍的抽象工厂模式将考虑多等级产品的生产，将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族，下图所示横轴是产品等级，也就是同一类产品；纵轴是产品族，也就是同一品牌的产品，同一品牌的产品产自同一个工厂。</p>
<img src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211291523354.png" style="zoom:67%;"/>
<img src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211291523937.png" style="zoom:67%;"/>
<h4 id="241-概念">
  2.4.1 概念
  <a class="anchor" href="#241-%e6%a6%82%e5%bf%b5">#</a>
</h4>
<p>是一种为访问类提供一个创建一组相关或相互依赖对象的接口，且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。</p>
<p>抽象工厂模式是工厂方法模式的升级版本，工厂方法模式只生产一个等级的产品，而抽象工厂模式可生产多个等级的产品。</p>
<h4 id="242-结构">
  2.4.2 结构
  <a class="anchor" href="#242-%e7%bb%93%e6%9e%84">#</a>
</h4>
<p>抽象工厂模式的主要角色如下：</p>
<ul>
<li>抽象工厂（Abstract Factory）：提供了创建产品的接口，它包含多个创建产品的方法，可以创建多个不同等级的产品。</li>
<li>具体工厂（Concrete Factory）：主要是实现抽象工厂中的多个抽象方法，完成具体产品的创建。</li>
<li>抽象产品（Product）：定义了产品的规范，描述了产品的主要特性和功能，抽象工厂模式有多个抽象产品。</li>
<li>具体产品（ConcreteProduct）：实现了抽象产品角色所定义的接口，由具体工厂来创建，它 同具体工厂之间是多对一的关系。</li>
</ul>
<h4 id="243-实现">
  2.4.3 实现
  <a class="anchor" href="#243-%e5%ae%9e%e7%8e%b0">#</a>
</h4>
<p>现咖啡店业务发生改变，不仅要生产咖啡还要生产甜点，如提拉米苏、抹茶慕斯等，要是按照工厂方法模式，需要定义提拉米苏类、抹茶慕斯类、提拉米苏工厂、抹茶慕斯工厂、甜点工厂类，很容易发生类爆炸情况。其中拿铁咖啡、美式咖啡是一个产品等级，都是咖啡；提拉米苏、抹茶慕斯也是一个产品等级；拿铁咖啡和提拉米苏是同一产品族（也就是都属于意大利风味），美式咖啡和抹茶慕斯是同一产品族（也就是都属于美式风味）。所以这个案例可以使用抽象工厂模式实现。类图如下：</p>
<img src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211291523377.png" style="zoom:67%;"/>
<p>代码如下：</p>
<p>抽象工厂：</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">interface</span> <span style="color:#a6e22e">DessertFactory</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    Coffee <span style="color:#a6e22e">createCoffee</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    Dessert <span style="color:#a6e22e">createDessert</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>具体工厂：</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">//美式甜点工厂
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">AmericanDessertFactory</span> <span style="color:#66d9ef">implements</span> DessertFactory <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Coffee <span style="color:#a6e22e">createCoffee</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> AmericanCoffee<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Dessert <span style="color:#a6e22e">createDessert</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> MatchaMousse<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//意大利风味甜点工厂
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">ItalyDessertFactory</span> <span style="color:#66d9ef">implements</span> DessertFactory <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Coffee <span style="color:#a6e22e">createCoffee</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> LatteCoffee<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Dessert <span style="color:#a6e22e">createDessert</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> Tiramisu<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>如果要加同一个产品族的话，只需要再加一个对应的工厂类即可，不需要修改其他的类。</p>
<p><strong>优点：</strong></p>
<p>当一个产品族中的多个对象被设计成一起工作时，它能保证客户端始终只使用同一个产品族中的对象。</p>
<p><strong>缺点：</strong></p>
<p>当产品族中需要增加一个新的产品时，所有的工厂类都需要进行修改。</p>
<h4 id="244-使用场景">
  2.4.4 使用场景
  <a class="anchor" href="#244-%e4%bd%bf%e7%94%a8%e5%9c%ba%e6%99%af">#</a>
</h4>
<ul>
<li>
<p>当需要创建的对象是一系列相互关联或相互依赖的产品族时，如电器工厂中的电视机、洗衣机、空调等。</p>
</li>
<li>
<p>系统中有多个产品族，但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。</p>
</li>
<li>
<p>系统中提供了产品的类库，且所有产品的接口相同，客户端不依赖产品实例的创建细节和内部结构。</p>
</li>
</ul>
<p>如：输入法换皮肤，一整套一起换。生成不同操作系统的程序。</p>
<h3 id="25-模式扩展">
  2.5 模式扩展
  <a class="anchor" href="#25-%e6%a8%a1%e5%bc%8f%e6%89%a9%e5%b1%95">#</a>
</h3>
<p><strong>简单工厂+配置文件解除耦合</strong></p>
<p>可以通过工厂模式+配置文件的方式解除工厂对象和产品对象的耦合。在工厂类中加载配置文件中的全类名，并创建对象进行存储，客户端如果需要对象，直接进行获取即可。</p>
<p>第一步：定义配置文件</p>
<p>为了演示方便，我们使用properties文件作为配置文件，名称为bean.properties</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-properties" data-lang="properties"><span style="display:flex;"><span><span style="color:#a6e22e">american</span><span style="color:#f92672">=</span><span style="color:#e6db74">com.itheima.pattern.factory.config_factory.AmericanCoffee</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">latte</span><span style="color:#f92672">=</span><span style="color:#e6db74">com.itheima.pattern.factory.config_factory.LatteCoffee</span>
</span></span></code></pre></div><p>第二步：改进工厂类</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">CoffeeFactory</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> Map<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">,</span>Coffee<span style="color:#f92672">&gt;</span> map <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> HashMap<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">static</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        Properties p <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Properties<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        InputStream is <span style="color:#f92672">=</span> CoffeeFactory<span style="color:#f92672">.</span><span style="color:#a6e22e">class</span><span style="color:#f92672">.</span><span style="color:#a6e22e">getClassLoader</span><span style="color:#f92672">().</span><span style="color:#a6e22e">getResourceAsStream</span><span style="color:#f92672">(</span><span style="color:#e6db74">"bean.properties"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">try</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            p<span style="color:#f92672">.</span><span style="color:#a6e22e">load</span><span style="color:#f92672">(</span>is<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>            <span style="color:#75715e">//遍历Properties集合对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>            Set<span style="color:#f92672">&lt;</span>Object<span style="color:#f92672">&gt;</span> keys <span style="color:#f92672">=</span> p<span style="color:#f92672">.</span><span style="color:#a6e22e">keySet</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">for</span> <span style="color:#f92672">(</span>Object key <span style="color:#f92672">:</span> keys<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>                <span style="color:#75715e">//根据键获取值（全类名）
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>                String className <span style="color:#f92672">=</span> p<span style="color:#f92672">.</span><span style="color:#a6e22e">getProperty</span><span style="color:#f92672">((</span>String<span style="color:#f92672">)</span> key<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>                <span style="color:#75715e">//获取字节码对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>                Class clazz <span style="color:#f92672">=</span> Class<span style="color:#f92672">.</span><span style="color:#a6e22e">forName</span><span style="color:#f92672">(</span>className<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>                Coffee obj <span style="color:#f92672">=</span> <span style="color:#f92672">(</span>Coffee<span style="color:#f92672">)</span> clazz<span style="color:#f92672">.</span><span style="color:#a6e22e">newInstance</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>                map<span style="color:#f92672">.</span><span style="color:#a6e22e">put</span><span style="color:#f92672">((</span>String<span style="color:#f92672">)</span>key<span style="color:#f92672">,</span>obj<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span> <span style="color:#66d9ef">catch</span> <span style="color:#f92672">(</span>Exception e<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            e<span style="color:#f92672">.</span><span style="color:#a6e22e">printStackTrace</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> Coffee <span style="color:#a6e22e">createCoffee</span><span style="color:#f92672">(</span>String name<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> map<span style="color:#f92672">.</span><span style="color:#a6e22e">get</span><span style="color:#f92672">(</span>name<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>静态成员变量用来存储创建的对象（键存储的是名称，值存储的是对应的对象），而读取配置文件以及创建对象写在静态代码块中，目的就是只需要执行一次。</p>
<h3 id="26-jdk源码解析-collectioniterator方法">
  2.6 JDK源码解析-Collection.iterator方法
  <a class="anchor" href="#26-jdk%e6%ba%90%e7%a0%81%e8%a7%a3%e6%9e%90-collectioniterator%e6%96%b9%e6%b3%95">#</a>
</h3>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Demo</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        List<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">&gt;</span> list <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ArrayList<span style="color:#f92672">&lt;&gt;();</span>
</span></span><span style="display:flex;"><span>        list<span style="color:#f92672">.</span><span style="color:#a6e22e">add</span><span style="color:#f92672">(</span><span style="color:#e6db74">"令狐冲"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        list<span style="color:#f92672">.</span><span style="color:#a6e22e">add</span><span style="color:#f92672">(</span><span style="color:#e6db74">"风清扬"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        list<span style="color:#f92672">.</span><span style="color:#a6e22e">add</span><span style="color:#f92672">(</span><span style="color:#e6db74">"任我行"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//获取迭代器对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Iterator<span style="color:#f92672">&lt;</span>String<span style="color:#f92672">&gt;</span> it <span style="color:#f92672">=</span> list<span style="color:#f92672">.</span><span style="color:#a6e22e">iterator</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//使用迭代器遍历
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        <span style="color:#66d9ef">while</span><span style="color:#f92672">(</span>it<span style="color:#f92672">.</span><span style="color:#a6e22e">hasNext</span><span style="color:#f92672">())</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            String ele <span style="color:#f92672">=</span> it<span style="color:#f92672">.</span><span style="color:#a6e22e">next</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>            System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>ele<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>对上面的代码大家应该很熟，使用迭代器遍历集合，获取集合中的元素。而单列集合获取迭代器的方法就使用到了工厂方法模式。我们看通过类图看看结构：</p>
<img src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211291523419.png" style="zoom:75%;"/>
<p>Collection接口是抽象工厂类，ArrayList是具体的工厂类；Iterator接口是抽象商品类，ArrayList类中的Iter内部类是具体的商品类。在具体的工厂类中iterator()方法创建具体的商品类的对象。</p>
<blockquote>
<p>另：</p>
<p>​	1 <code>DateForamt</code>类中的<code>getInstance()</code>方法使用的是工厂模式；</p>
<p>​	2 <code>Calendar</code>类中的<code>getInstance()</code>方法使用的是工厂模式；</p>
</blockquote>
<h2 id="3-原型模式">
  3 原型模式
  <a class="anchor" href="#3-%e5%8e%9f%e5%9e%8b%e6%a8%a1%e5%bc%8f">#</a>
</h2>
<h3 id="31-概述">
  3.1 概述
  <a class="anchor" href="#31-%e6%a6%82%e8%bf%b0">#</a>
</h3>
<p>用一个已经创建的实例作为原型，通过复制该原型对象来创建一个和原型对象相同的新对象。</p>
<h3 id="32-结构">
  3.2 结构
  <a class="anchor" href="#32-%e7%bb%93%e6%9e%84">#</a>
</h3>
<p>原型模式包含如下角色：</p>
<ul>
<li>抽象原型类：规定了具体原型对象必须实现的的 clone() 方法。</li>
<li>具体原型类：实现抽象原型类的 clone() 方法，它是可被复制的对象。</li>
<li>访问类：使用具体原型类中的 clone() 方法来复制新的对象。</li>
</ul>
<p>接口类图如下：</p>
<img alt="原型模式" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211291524995.png" style="zoom:80%;"/>
<p><strong>实现方式：</strong></p>
<p>原型模式的克隆分为浅克隆和深克隆。</p>
<blockquote>
<p>浅克隆：创建一个新对象，新对象的属性和原来对象完全相同，对于非基本类型属性，仍指向原有属性所指向的对象的内存地址。</p>
<p>深克隆：创建一个新对象，属性中引用的其他对象也会被克隆，不再指向原有对象地址。</p>
</blockquote>
<p>Java中的Object类中提供了 <code>clone()</code> 方法来实现浅克隆。 Cloneable 接口是上面的类图中的抽象原型类，而实现了Cloneable接口的子实现类就是具体的原型类。代码如下：</p>
<p><strong>Realizetype（具体的原型类）：</strong></p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Realizetype</span> <span style="color:#66d9ef">implements</span> Cloneable <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">Realizetype</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"具体的原型对象创建完成！"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">protected</span> Realizetype <span style="color:#a6e22e">clone</span><span style="color:#f92672">()</span> <span style="color:#66d9ef">throws</span> CloneNotSupportedException <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"具体原型复制成功！"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#f92672">(</span>Realizetype<span style="color:#f92672">)</span> <span style="color:#66d9ef">super</span><span style="color:#f92672">.</span><span style="color:#a6e22e">clone</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><strong>PrototypeTest（测试访问类）：</strong></p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">PrototypeTest</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> CloneNotSupportedException <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        Realizetype r1 <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Realizetype<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        Realizetype r2 <span style="color:#f92672">=</span> r1<span style="color:#f92672">.</span><span style="color:#a6e22e">clone</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"对象r1和r2是同一个对象？"</span> <span style="color:#f92672">+</span> <span style="color:#f92672">(</span>r1 <span style="color:#f92672">==</span> r2<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<h3 id="33-案例">
  3.3 案例
  <a class="anchor" href="#33-%e6%a1%88%e4%be%8b">#</a>
</h3>
<p><strong>用原型模式生成“三好学生”奖状</strong> ：同一学校的“三好学生”奖状除了获奖人姓名不同，其他都相同，可以使用原型模式复制多个“三好学生”奖状出来，然后在修改奖状上的名字即可。</p>
<p>类图如下：</p>
<img alt="原型模式1" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211291524464.png" style="zoom:80%;"/>
<p>代码如下：</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">//奖状类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Citation</span> <span style="color:#66d9ef">implements</span> Cloneable <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String name<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">setName</span><span style="color:#f92672">(</span>String name<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">name</span> <span style="color:#f92672">=</span> name<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">getName</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#f92672">(</span><span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">name</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">show</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>name <span style="color:#f92672">+</span> <span style="color:#e6db74">"同学：在2020学年第一学期中表现优秀，被评为三好学生。特发此状！"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Citation <span style="color:#a6e22e">clone</span><span style="color:#f92672">()</span> <span style="color:#66d9ef">throws</span> CloneNotSupportedException <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#f92672">(</span>Citation<span style="color:#f92672">)</span> <span style="color:#66d9ef">super</span><span style="color:#f92672">.</span><span style="color:#a6e22e">clone</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//测试访问类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">CitationTest</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> CloneNotSupportedException <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        Citation c1 <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Citation<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        c1<span style="color:#f92672">.</span><span style="color:#a6e22e">setName</span><span style="color:#f92672">(</span><span style="color:#e6db74">"张三"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//复制奖状
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Citation c2 <span style="color:#f92672">=</span> c1<span style="color:#f92672">.</span><span style="color:#a6e22e">clone</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//将奖状的名字修改李四
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        c2<span style="color:#f92672">.</span><span style="color:#a6e22e">setName</span><span style="color:#f92672">(</span><span style="color:#e6db74">"李四"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        c1<span style="color:#f92672">.</span><span style="color:#a6e22e">show</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        c2<span style="color:#f92672">.</span><span style="color:#a6e22e">show</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<h3 id="34-使用场景">
  3.4 使用场景
  <a class="anchor" href="#34-%e4%bd%bf%e7%94%a8%e5%9c%ba%e6%99%af">#</a>
</h3>
<ul>
<li>对象的创建非常复杂，可以使用原型模式快捷的创建对象。</li>
<li>性能和安全要求比较高。</li>
</ul>
<h3 id="35-扩展深克隆">
  3.5 扩展（深克隆）
  <a class="anchor" href="#35-%e6%89%a9%e5%b1%95%e6%b7%b1%e5%85%8b%e9%9a%86">#</a>
</h3>
<p>将上面的“三好学生”奖状的案例中Citation类的name属性修改为Student类型的属性。代码如下：</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">//奖状类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Citation</span> <span style="color:#66d9ef">implements</span> Cloneable <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> Student stu<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Student <span style="color:#a6e22e">getStu</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> stu<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">setStu</span><span style="color:#f92672">(</span>Student stu<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">stu</span> <span style="color:#f92672">=</span> stu<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">show</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>stu<span style="color:#f92672">.</span><span style="color:#a6e22e">getName</span><span style="color:#f92672">()</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">"同学：在2020学年第一学期中表现优秀，被评为三好学生。特发此状！"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Citation <span style="color:#a6e22e">clone</span><span style="color:#f92672">()</span> <span style="color:#66d9ef">throws</span> CloneNotSupportedException <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#f92672">(</span>Citation<span style="color:#f92672">)</span> <span style="color:#66d9ef">super</span><span style="color:#f92672">.</span><span style="color:#a6e22e">clone</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//学生类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Student</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String name<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String address<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">Student</span><span style="color:#f92672">(</span>String name<span style="color:#f92672">,</span> String address<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">name</span> <span style="color:#f92672">=</span> name<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">address</span> <span style="color:#f92672">=</span> address<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">Student</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">getName</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> name<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">setName</span><span style="color:#f92672">(</span>String name<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">name</span> <span style="color:#f92672">=</span> name<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">getAddress</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> address<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">setAddress</span><span style="color:#f92672">(</span>String address<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">address</span> <span style="color:#f92672">=</span> address<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//测试类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">CitationTest</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> CloneNotSupportedException <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        Citation c1 <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Citation<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        Student stu <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Student<span style="color:#f92672">(</span><span style="color:#e6db74">"张三"</span><span style="color:#f92672">,</span> <span style="color:#e6db74">"西安"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        c1<span style="color:#f92672">.</span><span style="color:#a6e22e">setStu</span><span style="color:#f92672">(</span>stu<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//复制奖状
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Citation c2 <span style="color:#f92672">=</span> c1<span style="color:#f92672">.</span><span style="color:#a6e22e">clone</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//获取c2奖状所属学生对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Student stu1 <span style="color:#f92672">=</span> c2<span style="color:#f92672">.</span><span style="color:#a6e22e">getStu</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        stu1<span style="color:#f92672">.</span><span style="color:#a6e22e">setName</span><span style="color:#f92672">(</span><span style="color:#e6db74">"李四"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//判断stu对象和stu1对象是否是同一个对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"stu和stu1是同一个对象？"</span> <span style="color:#f92672">+</span> <span style="color:#f92672">(</span>stu <span style="color:#f92672">==</span> stu1<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        c1<span style="color:#f92672">.</span><span style="color:#a6e22e">show</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        c2<span style="color:#f92672">.</span><span style="color:#a6e22e">show</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>运行结果为：</p>
<p>
<img alt="原型模式2" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211291525793.png"/></p>
<p><font color="red">说明：</font></p>
<p>​	<code>stu</code> 对象和 <code>stu1</code> 对象是同一个对象，就会产生将stu1对象中name属性值改为“李四”，两个Citation（奖状）对象中显示的都是李四。这就是浅克隆的效果，对具体原型类（Citation）中的引用类型的属性进行引用的复制。这种情况需要使用深克隆，而进行深克隆需要使用对象流。代码如下：</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">CitationTest1</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> Exception <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        Citation c1 <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Citation<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        Student stu <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Student<span style="color:#f92672">(</span><span style="color:#e6db74">"张三"</span><span style="color:#f92672">,</span> <span style="color:#e6db74">"西安"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        c1<span style="color:#f92672">.</span><span style="color:#a6e22e">setStu</span><span style="color:#f92672">(</span>stu<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//创建对象输出流对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        ObjectOutputStream oos <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ObjectOutputStream<span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> FileOutputStream<span style="color:#f92672">(</span><span style="color:#e6db74">"C:\\Users\\Think\\Desktop\\b.txt"</span><span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//将c1对象写出到文件中
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        oos<span style="color:#f92672">.</span><span style="color:#a6e22e">writeObject</span><span style="color:#f92672">(</span>c1<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        oos<span style="color:#f92672">.</span><span style="color:#a6e22e">close</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//创建对象出入流对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        ObjectInputStream ois <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> ObjectInputStream<span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> FileInputStream<span style="color:#f92672">(</span><span style="color:#e6db74">"C:\\Users\\Think\\Desktop\\b.txt"</span><span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//读取对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Citation c2 <span style="color:#f92672">=</span> <span style="color:#f92672">(</span>Citation<span style="color:#f92672">)</span> ois<span style="color:#f92672">.</span><span style="color:#a6e22e">readObject</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//获取c2奖状所属学生对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Student stu1 <span style="color:#f92672">=</span> c2<span style="color:#f92672">.</span><span style="color:#a6e22e">getStu</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        stu1<span style="color:#f92672">.</span><span style="color:#a6e22e">setName</span><span style="color:#f92672">(</span><span style="color:#e6db74">"李四"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//判断stu对象和stu1对象是否是同一个对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span><span style="color:#e6db74">"stu和stu1是同一个对象？"</span> <span style="color:#f92672">+</span> <span style="color:#f92672">(</span>stu <span style="color:#f92672">==</span> stu1<span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        c1<span style="color:#f92672">.</span><span style="color:#a6e22e">show</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        c2<span style="color:#f92672">.</span><span style="color:#a6e22e">show</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>运行结果为：</p>
<p>
<img alt="原型模式3" src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211291525812.png"/></p>
<blockquote>
<p>注意：<code>Citation</code>类和<code>Student</code>类必须实现<code>Serializable</code>接口，否则会抛<code>NotSerializableException</code>异常。</p>
</blockquote>
<h2 id="4-建造者模式">
  4 建造者模式
  <a class="anchor" href="#4-%e5%bb%ba%e9%80%a0%e8%80%85%e6%a8%a1%e5%bc%8f">#</a>
</h2>
<h3 id="41-概述">
  4.1 概述
  <a class="anchor" href="#41-%e6%a6%82%e8%bf%b0">#</a>
</h3>
<p>将一个复杂对象的构建与表示分离，使得同样的构建过程可以创建不同的表示。</p>
<img src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211291525327.png" style="zoom:60%;"/>
<ul>
<li>分离了部件的构造(由Builder来负责)和装配(由Director负责)。 从而可以构造出复杂的对象。这个模式适用于：某个对象的构建过程复杂的情况。</li>
<li>由于实现了构建和装配的解耦。不同的构建器，相同的装配，也可以做出不同的对象；相同的构建器，不同的装配顺序也可以做出不同的对象。也就是实现了构建算法、装配算法的解耦，实现了更好的复用。</li>
<li>建造者模式可以将部件和其组装过程分开，一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象，而无须知道其内部的具体构造细节。</li>
</ul>
<h3 id="42-结构">
  4.2 结构
  <a class="anchor" href="#42-%e7%bb%93%e6%9e%84">#</a>
</h3>
<p>建造者（Builder）模式包含如下角色：</p>
<ul>
<li>
<p>抽象建造者类（Builder）：这个接口规定要实现复杂对象的那些部分的创建，并不涉及具体的部件对象的创建。</p>
</li>
<li>
<p>具体建造者类（ConcreteBuilder）：实现 Builder 接口，完成复杂产品的各个部件的具体创建方法。在构造过程完成后，提供产品的实例。</p>
</li>
<li>
<p>产品类（Product）：要创建的复杂对象。</p>
</li>
<li>
<p>指挥者类（Director）：调用具体建造者来创建复杂对象的各个部分，在指导者中不涉及具体产品的信息，只负责保证对象各部分完整创建或按某种顺序创建。</p>
</li>
</ul>
<p>类图如下：</p>
<img src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211291525950.png" style="zoom:80%;"/>
<h3 id="43-实例">
  4.3 实例
  <a class="anchor" href="#43-%e5%ae%9e%e4%be%8b">#</a>
</h3>
<p><strong>创建共享单车</strong></p>
<p>生产自行车是一个复杂的过程，它包含了车架，车座等组件的生产。而车架又有碳纤维，铝合金等材质的，车座有橡胶，真皮等材质。对于自行车的生产就可以使用建造者模式。</p>
<p>这里Bike是产品，包含车架，车座等组件；Builder是抽象建造者，MobikeBuilder和OfoBuilder是具体的建造者；Director是指挥者。类图如下：</p>
<img src="https://blog-1256273063.cos.ap-nanjing.myqcloud.com/202211291525015.png" style="zoom:80%;"/>
<p>具体的代码如下：</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">//自行车类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Bike</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String frame<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String seat<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">getFrame</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> frame<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">setFrame</span><span style="color:#f92672">(</span>String frame<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">frame</span> <span style="color:#f92672">=</span> frame<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">getSeat</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> seat<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">setSeat</span><span style="color:#f92672">(</span>String seat<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">seat</span> <span style="color:#f92672">=</span> seat<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// 抽象 builder 类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">abstract</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Builder</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">protected</span> Bike mBike <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Bike<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">abstract</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">buildFrame</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">abstract</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">buildSeat</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">abstract</span> Bike <span style="color:#a6e22e">createBike</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//摩拜单车Builder类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">MobikeBuilder</span> <span style="color:#66d9ef">extends</span> Builder <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">buildFrame</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        mBike<span style="color:#f92672">.</span><span style="color:#a6e22e">setFrame</span><span style="color:#f92672">(</span><span style="color:#e6db74">"铝合金车架"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">buildSeat</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        mBike<span style="color:#f92672">.</span><span style="color:#a6e22e">setSeat</span><span style="color:#f92672">(</span><span style="color:#e6db74">"真皮车座"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Bike <span style="color:#a6e22e">createBike</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> mBike<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//ofo单车Builder类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">OfoBuilder</span> <span style="color:#66d9ef">extends</span> Builder <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">buildFrame</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        mBike<span style="color:#f92672">.</span><span style="color:#a6e22e">setFrame</span><span style="color:#f92672">(</span><span style="color:#e6db74">"碳纤维车架"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">buildSeat</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        mBike<span style="color:#f92672">.</span><span style="color:#a6e22e">setSeat</span><span style="color:#f92672">(</span><span style="color:#e6db74">"橡胶车座"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Bike <span style="color:#a6e22e">createBike</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> mBike<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//指挥者类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Director</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> Builder mBuilder<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">Director</span><span style="color:#f92672">(</span>Builder builder<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        mBuilder <span style="color:#f92672">=</span> builder<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Bike <span style="color:#a6e22e">construct</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        mBuilder<span style="color:#f92672">.</span><span style="color:#a6e22e">buildFrame</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        mBuilder<span style="color:#f92672">.</span><span style="color:#a6e22e">buildSeat</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> mBuilder<span style="color:#f92672">.</span><span style="color:#a6e22e">createBike</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">//测试类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Client</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        showBike<span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> OfoBuilder<span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        showBike<span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> MobikeBuilder<span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">showBike</span><span style="color:#f92672">(</span>Builder builder<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        Director director <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Director<span style="color:#f92672">(</span>builder<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        Bike bike <span style="color:#f92672">=</span> director<span style="color:#f92672">.</span><span style="color:#a6e22e">construct</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>bike<span style="color:#f92672">.</span><span style="color:#a6e22e">getFrame</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>bike<span style="color:#f92672">.</span><span style="color:#a6e22e">getSeat</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><strong>注意：</strong></p>
<p>上面示例是 Builder模式的常规用法，指挥者类 Director 在建造者模式中具有很重要的作用，它用于指导具体构建者如何构建产品，控制调用先后次序，并向调用者返回完整的产品类，但是有些情况下需要简化系统结构，可以把指挥者类和抽象建造者进行结合</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#75715e">// 抽象 builder 类
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">abstract</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Builder</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">protected</span> Bike mBike <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Bike<span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">abstract</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">buildFrame</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">abstract</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">buildSeat</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">abstract</span> Bike <span style="color:#a6e22e">createBike</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Bike <span style="color:#a6e22e">construct</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">buildFrame</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">BuildSeat</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">createBike</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p><strong>说明：</strong></p>
<p>这样做确实简化了系统结构，但同时也加重了抽象建造者类的职责，也不是太符合单一职责原则，如果construct() 过于复杂，建议还是封装到 Director 中。</p>
<p><strong>优点：</strong></p>
<ul>
<li>建造者模式的封装性很好。使用建造者模式可以有效的封装变化，在使用建造者模式的场景中，一般产品类和建造者类是比较稳定的，因此，将主要的业务逻辑封装在指挥者类中对整体而言可以取得比较好的稳定性。</li>
<li>在建造者模式中，客户端不必知道产品内部组成的细节，将产品本身与产品的创建过程解耦，使得相同的创建过程可以创建不同的产品对象。</li>
<li>可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中，使得创建过程更加清晰，也更方便使用程序来控制创建过程。</li>
<li>建造者模式很容易进行扩展。如果有新的需求，通过实现一个新的建造者类就可以完成，基本上不用修改之前已经测试通过的代码，因此也就不会对原有功能引入风险。符合开闭原则。</li>
</ul>
<p><strong>缺点：</strong></p>
<p>造者模式所创建的产品一般具有较多的共同点，其组成部分相似，如果产品之间的差异性很大，则不适合使用建造者模式，因此其使用范围受到一定的限制。</p>
<h3 id="44-使用场景">
  4.4 使用场景
  <a class="anchor" href="#44-%e4%bd%bf%e7%94%a8%e5%9c%ba%e6%99%af">#</a>
</h3>
<p>建造者（Builder）模式创建的是复杂对象，其产品的各个部分经常面临着剧烈的变化，但将它们组合在一起的算法却相对稳定，所以它通常在以下场合使用。</p>
<ul>
<li>创建的对象较复杂，由多个部件构成，各部件面临着复杂的变化，但构件间的建造顺序是稳定的。</li>
<li>创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式，即产品的构建过程和最终的表示是独立的。</li>
</ul>
<h3 id="45-模式扩展">
  4.5 模式扩展
  <a class="anchor" href="#45-%e6%a8%a1%e5%bc%8f%e6%89%a9%e5%b1%95">#</a>
</h3>
<p>建造者模式除了上面的用途外，在开发中还有一个常用的使用方式，就是当一个类构造器需要传入很多参数时，如果创建这个类的实例，代码可读性会非常差，而且很容易引入错误，此时就可以利用建造者模式进行重构。</p>
<p>重构前代码如下：</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Phone</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String cpu<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String screen<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String memory<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String mainboard<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">Phone</span><span style="color:#f92672">(</span>String cpu<span style="color:#f92672">,</span> String screen<span style="color:#f92672">,</span> String memory<span style="color:#f92672">,</span> String mainboard<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">cpu</span> <span style="color:#f92672">=</span> cpu<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">screen</span> <span style="color:#f92672">=</span> screen<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">memory</span> <span style="color:#f92672">=</span> memory<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">mainboard</span> <span style="color:#f92672">=</span> mainboard<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">getCpu</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> cpu<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">setCpu</span><span style="color:#f92672">(</span>String cpu<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">cpu</span> <span style="color:#f92672">=</span> cpu<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">getScreen</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> screen<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">setScreen</span><span style="color:#f92672">(</span>String screen<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">screen</span> <span style="color:#f92672">=</span> screen<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">getMemory</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> memory<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">setMemory</span><span style="color:#f92672">(</span>String memory<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">memory</span> <span style="color:#f92672">=</span> memory<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">getMainboard</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> mainboard<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">setMainboard</span><span style="color:#f92672">(</span>String mainboard<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">this</span><span style="color:#f92672">.</span><span style="color:#a6e22e">mainboard</span> <span style="color:#f92672">=</span> mainboard<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">toString</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">"Phone{"</span> <span style="color:#f92672">+</span>
</span></span><span style="display:flex;"><span>                <span style="color:#e6db74">"cpu='"</span> <span style="color:#f92672">+</span> cpu <span style="color:#f92672">+</span> <span style="color:#e6db74">'\''</span> <span style="color:#f92672">+</span>
</span></span><span style="display:flex;"><span>                <span style="color:#e6db74">", screen='"</span> <span style="color:#f92672">+</span> screen <span style="color:#f92672">+</span> <span style="color:#e6db74">'\''</span> <span style="color:#f92672">+</span>
</span></span><span style="display:flex;"><span>                <span style="color:#e6db74">", memory='"</span> <span style="color:#f92672">+</span> memory <span style="color:#f92672">+</span> <span style="color:#e6db74">'\''</span> <span style="color:#f92672">+</span>
</span></span><span style="display:flex;"><span>                <span style="color:#e6db74">", mainboard='"</span> <span style="color:#f92672">+</span> mainboard <span style="color:#f92672">+</span> <span style="color:#e6db74">'\''</span> <span style="color:#f92672">+</span>
</span></span><span style="display:flex;"><span>                <span style="color:#e6db74">'}'</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Client</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//构建Phone对象
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        Phone phone <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Phone<span style="color:#f92672">(</span><span style="color:#e6db74">"intel"</span><span style="color:#f92672">,</span><span style="color:#e6db74">"三星屏幕"</span><span style="color:#f92672">,</span><span style="color:#e6db74">"金士顿"</span><span style="color:#f92672">,</span><span style="color:#e6db74">"华硕"</span><span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>phone<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>上面在客户端代码中构建Phone对象，传递了四个参数，如果参数更多呢？代码的可读性及使用的成本就是比较高。</p>
<p>重构后代码：</p>
<div class="book-expand">
<label>
<div class="book-expand-head flex justify-between">
<span>点击展开</span>
<span>...</span>
</div>
<input class="hidden" type="checkbox"/>
<div class="book-expand-content markdown-inner">
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;" tabindex="0"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Phone</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String cpu<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String screen<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String memory<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> String mainboard<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#a6e22e">Phone</span><span style="color:#f92672">(</span>Builder builder<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        cpu <span style="color:#f92672">=</span> builder<span style="color:#f92672">.</span><span style="color:#a6e22e">cpu</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        screen <span style="color:#f92672">=</span> builder<span style="color:#f92672">.</span><span style="color:#a6e22e">screen</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        memory <span style="color:#f92672">=</span> builder<span style="color:#f92672">.</span><span style="color:#a6e22e">memory</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        mainboard <span style="color:#f92672">=</span> builder<span style="color:#f92672">.</span><span style="color:#a6e22e">mainboard</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">final</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Builder</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">private</span> String cpu<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">private</span> String screen<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">private</span> String memory<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">private</span> String mainboard<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> <span style="color:#a6e22e">Builder</span><span style="color:#f92672">()</span> <span style="color:#f92672">{}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> Builder <span style="color:#a6e22e">cpu</span><span style="color:#f92672">(</span>String val<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            cpu <span style="color:#f92672">=</span> val<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">this</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> Builder <span style="color:#a6e22e">screen</span><span style="color:#f92672">(</span>String val<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            screen <span style="color:#f92672">=</span> val<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">this</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> Builder <span style="color:#a6e22e">memory</span><span style="color:#f92672">(</span>String val<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            memory <span style="color:#f92672">=</span> val<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">this</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> Builder <span style="color:#a6e22e">mainboard</span><span style="color:#f92672">(</span>String val<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            mainboard <span style="color:#f92672">=</span> val<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">this</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">public</span> Phone <span style="color:#a6e22e">build</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>            <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> Phone<span style="color:#f92672">(</span><span style="color:#66d9ef">this</span><span style="color:#f92672">);}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Override</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> String <span style="color:#a6e22e">toString</span><span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#e6db74">"Phone{"</span> <span style="color:#f92672">+</span>
</span></span><span style="display:flex;"><span>                <span style="color:#e6db74">"cpu='"</span> <span style="color:#f92672">+</span> cpu <span style="color:#f92672">+</span> <span style="color:#e6db74">'\''</span> <span style="color:#f92672">+</span>
</span></span><span style="display:flex;"><span>                <span style="color:#e6db74">", screen='"</span> <span style="color:#f92672">+</span> screen <span style="color:#f92672">+</span> <span style="color:#e6db74">'\''</span> <span style="color:#f92672">+</span>
</span></span><span style="display:flex;"><span>                <span style="color:#e6db74">", memory='"</span> <span style="color:#f92672">+</span> memory <span style="color:#f92672">+</span> <span style="color:#e6db74">'\''</span> <span style="color:#f92672">+</span>
</span></span><span style="display:flex;"><span>                <span style="color:#e6db74">", mainboard='"</span> <span style="color:#f92672">+</span> mainboard <span style="color:#f92672">+</span> <span style="color:#e6db74">'\''</span> <span style="color:#f92672">+</span>
</span></span><span style="display:flex;"><span>                <span style="color:#e6db74">'}'</span><span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Client</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">main</span><span style="color:#f92672">(</span>String<span style="color:#f92672">[]</span> args<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        Phone phone <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Phone<span style="color:#f92672">.</span><span style="color:#a6e22e">Builder</span><span style="color:#f92672">()</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">.</span><span style="color:#a6e22e">cpu</span><span style="color:#f92672">(</span><span style="color:#e6db74">"intel"</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">.</span><span style="color:#a6e22e">mainboard</span><span style="color:#f92672">(</span><span style="color:#e6db74">"华硕"</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">.</span><span style="color:#a6e22e">memory</span><span style="color:#f92672">(</span><span style="color:#e6db74">"金士顿"</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">.</span><span style="color:#a6e22e">screen</span><span style="color:#f92672">(</span><span style="color:#e6db74">"三星"</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">.</span><span style="color:#a6e22e">build</span><span style="color:#f92672">();</span>
</span></span><span style="display:flex;"><span>        System<span style="color:#f92672">.</span><span style="color:#a6e22e">out</span><span style="color:#f92672">.</span><span style="color:#a6e22e">println</span><span style="color:#f92672">(</span>phone<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div>
</div>
</label>
</div>
<p>重构后的代码在使用起来更方便，某种程度上也可以提高开发效率。从软件设计上，对程序员的要求比较高。</p>
<h3 id="46-创建者模式对比">
  4.6 创建者模式对比
  <a class="anchor" href="#46-%e5%88%9b%e5%bb%ba%e8%80%85%e6%a8%a1%e5%bc%8f%e5%af%b9%e6%af%94">#</a>
</h3>
<h4 id="461-工厂方法模式vs建造者模式">
  4.6.1 工厂方法模式VS建造者模式
  <a class="anchor" href="#461-%e5%b7%a5%e5%8e%82%e6%96%b9%e6%b3%95%e6%a8%a1%e5%bc%8fvs%e5%bb%ba%e9%80%a0%e8%80%85%e6%a8%a1%e5%bc%8f">#</a>
</h4>
<p>工厂方法模式注重的是整体对象的创建方式；而建造者模式注重的是部件构建的过程，意在通过一步一步地精确构造创建出一个复杂的对象。</p>
<p>我们举个简单例子来说明两者的差异，如要制造一个超人，如果使用工厂方法模式，直接产生出来的就是一个力大无穷、能够飞翔、内裤外穿的超人；而如果使用建造者模式，则需要组装手、头、脚、躯干等部分，然后再把内裤外穿，于是一个超人就诞生了。</p>
<h4 id="462-抽象工厂模式vs建造者模式">
  4.6.2 抽象工厂模式VS建造者模式
  <a class="anchor" href="#462-%e6%8a%bd%e8%b1%a1%e5%b7%a5%e5%8e%82%e6%a8%a1%e5%bc%8fvs%e5%bb%ba%e9%80%a0%e8%80%85%e6%a8%a1%e5%bc%8f">#</a>
</h4>
<p>抽象工厂模式实现对产品家族的创建，一个产品家族是这样的一系列产品：具有不同分类维度的产品组合，采用抽象工厂模式则是不需要关心构建过程，只关心什么产品由什么工厂生产即可。</p>
<p>建造者模式则是要求按照指定的蓝图建造产品，它的主要目的是通过组装零配件而产生一个新产品。</p>
<p>如果将抽象工厂模式看成汽车配件生产工厂，生产一个产品族的产品，那么建造者模式就是一个汽车组装工厂，通过对部件的组装可以返回一辆完整的汽车。</p>
</article>
<footer class="book-footer">
<div class="flex flex-wrap justify-between">
</div>
<script>(function(){function e(e){const t=window.getSelection(),n=document.createRange();n.selectNodeContents(e),t.removeAllRanges(),t.addRange(n)}document.querySelectorAll("pre code").forEach(t=>{t.addEventListener("click",function(){if(window.getSelection().toString())return;e(t.parentElement),navigator.clipboard&&navigator.clipboard.writeText(t.parentElement.textContent)})})})()</script>
</footer>
<div class="book-comments">
</div>
<label class="hidden book-menu-overlay" for="menu-control"></label>
</div>
<aside class="book-toc">
<div class="book-toc-content">
<nav id="TableOfContents">
<ul>
<li><a href="#创建型模式">创建型模式</a>
<ul>
<li><a href="#1-单例设计模式">1 单例设计模式</a>
<ul>
<li><a href="#11-概述">1.1 概述</a></li>
<li><a href="#12-结构">1.2 结构</a></li>
<li><a href="#13-案例实现">1.3 案例实现</a>
<ul>
<li><a href="#121-饿汉式">1.2.1 饿汉式</a></li>
<li><a href="#122-懒汉式">1.2.2 懒汉式</a></li>
<li><a href="#123-枚举方式">1.2.3 枚举方式</a></li>
</ul>
</li>
<li><a href="#14-jdk源码解析-runtime类">1.4 JDK源码解析-Runtime类</a></li>
<li><a href="#15-存在的问题">1.5 存在的问题</a>
<ul>
<li><a href="#151-问题演示">1.5.1 问题演示</a></li>
<li><a href="#152-问题的解决">1.5.2 问题的解决</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#2-工厂模式">2 工厂模式</a>
<ul>
<li><a href="#21-概述">2.1 概述</a></li>
<li><a href="#22-简单工厂模式">2.2 简单工厂模式</a>
<ul>
<li><a href="#221-概念">2.2.1 概念</a></li>
<li><a href="#222-结构">2.2.2 结构</a></li>
<li><a href="#223-实现">2.2.3 实现</a></li>
<li><a href="#224-扩展">2.2.4 扩展</a></li>
</ul>
</li>
<li><a href="#23-工厂方法模式">2.3 工厂方法模式</a>
<ul>
<li><a href="#231-概念">2.3.1 概念</a></li>
<li><a href="#232-结构">2.3.2 结构</a></li>
<li><a href="#233-实现">2.3.3 实现</a></li>
</ul>
</li>
<li><a href="#24-抽象工厂模式">2.4 抽象工厂模式</a>
<ul>
<li><a href="#241-概念">2.4.1 概念</a></li>
<li><a href="#242-结构">2.4.2 结构</a></li>
<li><a href="#243-实现">2.4.3 实现</a></li>
<li><a href="#244-使用场景">2.4.4 使用场景</a></li>
</ul>
</li>
<li><a href="#25-模式扩展">2.5 模式扩展</a></li>
<li><a href="#26-jdk源码解析-collectioniterator方法">2.6 JDK源码解析-Collection.iterator方法</a></li>
</ul>
</li>
<li><a href="#3-原型模式">3 原型模式</a>
<ul>
<li><a href="#31-概述">3.1 概述</a></li>
<li><a href="#32-结构">3.2 结构</a></li>
<li><a href="#33-案例">3.3 案例</a></li>
<li><a href="#34-使用场景">3.4 使用场景</a></li>
<li><a href="#35-扩展深克隆">3.5 扩展（深克隆）</a></li>
</ul>
</li>
<li><a href="#4-建造者模式">4 建造者模式</a>
<ul>
<li><a href="#41-概述">4.1 概述</a></li>
<li><a href="#42-结构">4.2 结构</a></li>
<li><a href="#43-实例">4.3 实例</a></li>
<li><a href="#44-使用场景">4.4 使用场景</a></li>
<li><a href="#45-模式扩展">4.5 模式扩展</a></li>
<li><a href="#46-创建者模式对比">4.6 创建者模式对比</a>
<ul>
<li><a href="#461-工厂方法模式vs建造者模式">4.6.1 工厂方法模式VS建造者模式</a></li>
<li><a href="#462-抽象工厂模式vs建造者模式">4.6.2 抽象工厂模式VS建造者模式</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
</div>
</aside>
</main>
</body>
</html>
